Java - 18 (JAVA8 람다)

hoegon kim·2022년 12월 13일
0

JAVA

목록 보기
18/26
post-thumbnail

71) 람다 표현식


람다 표현식(lambda expression)이란?

람다 표현식(lambda expression)이란 간단히 말해 메소드를 하나의 식으로 표현한 것 입니다.

메소드

int min(int x, int y){
	return x < y? x:y;
}

람다 표현식

(x,y) -> x < y ? x:y;

위의 예제처럼 메소드를 람다 표현식으로 표현하면, 클래스를 작성하고 객체를 생성하지 않아도 메소드를 사용할 수 있습니다.

그런데 자바에서는 클래스의 선언과 동시에 객체를 생성하므로, 단 하나의 객체만들 생성할 수 있는 클래스를 익명 클래스라고 합니다.

따라서 자바에서 람다 표현식은 익명 클래스와 같다고 할 수 있습니다.

람다 표현식

(x,y) -> x < y? x:y;

익명 클래스

new Object() {
	int min(int x, int y){
    	return x < y ? x : y;   	 
	}
}

이러한 람다 표현식은 메소드의 매개변수로 전달 될 수도 있으며, 메소드의 결괏값으로 반환 될 수도 있습니다.

따라서 람다 표현식을 사용하면, 기존의 불필요한 코드를 줄여주고, 작성된 코드의 가독성을 높여줍니다.

JavaSE 8부터는 이러한 람다 표현식을 사용하여 자바에서도 함수형 프로그램밍을 할 수 있게 되었습니다.


람다 표현식 작성

자바에서는 화살표 -> 기호를 사용하여 람다 표현식을 작성할 수 있습니다.

(매개변수목록) -> {함수 몸체}

자바에서 람다 표현식을 작성할 때 유의해야 할 사항은 다음과 같습니다.

  1. 매개변수의 타입을 추론할 수 있는 경우에는 타입을 생략할 수 있습니다.

  2. 매개변수가 하나인 경우에는 괄호(())를 생략할 수 있습니다.

  3. 함수의 몸체가 하나의 명령문만으로 이루어진 경우에는 중괄호({})를 생략할 수 있습니다. (이때 세미콜론(;)은 붙이지 않음)

  4. 함수의 몸체가 하나의 return문으로만 이루어진 경우에는 중괄호({})를 생략할 수 없습니다.

  5. return문 대신 표현식을 사용할 수 있으며, 이때 반환값은 표현식의 결괏값이 됩니다. (이때 세미콜론(;)은 붙이지 않음)

다음 예제는 전통적인 방식의 스레드 생성과 람다 표현식을 사용한 스레드 생성을 비교하는 예제입니다.

new Thread(new Runnable() {

    public void run() {

        System.out.println("전통적인 방식의 일회용 스레드 생성");

    }

}).start();

 

new Thread(()->{

    System.out.println("람다 표현식을 사용한 일회용 스레드 생성");

}).start();

결과

전통적인 방식의 일회용 스레드 생성
람다 표현식을 사용한 일회용 스레드 생성

위의 예제에서 볼 수 있듯이 람다 표현식을 사용하면 불필요한 코드를 줄일 수 있으며, 코드의 가독성이 훨씬 좋아집니다.


함수형 인터페이스(functional interface)

람다 표현식을 사용할 때는 람다 표현식을 저장하기 위한 참조 변수의 타입을 결정해야만 합니다.

문법

참조변수의타입 참조변수의 이름 = 람다 표현식

위의 문법처럼 람다 표현식을 하나의 변수에 대입할 때 사용하는 참조 변수의 타입을 함수형 인터페이스라고 부릅니다.

함수형 인터페이스는 추상 클래스와는 달리 단 하나의 추상 메소드만을 가져야 합니다.

또한, 다음과 같은 어노테이션을 사용하여 함수형 인터페이스임을 명시할 수 있습니다.

@FunctionalInterface

interface Calc { // 함수형 인터페이스의 선언

    public int min(int x, int y);

}

 

public class Lambda02 {

public static void main(String[] args){

        Calc minNum = (x, y) -> x < y ? x : y; // 추상 메소드의 구현

        System.out.println(minNum.min(3, 4));  // 함수형 인터페이스의 사용

    }

}

결과

3

자바는 java.util.function 패키지를 통해 여러 상황에서 사용할 수 있는 다양한 함수형 인터페이스를 미리 정의하여 제공합니다.

java.util.function 패키지에 대한 더 자세한 사항은 다음 페이지를 참고하면 됩니다.

http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html


72) 메소드 참조

메소드 참조(method reference)

메소드 참조는 람다 표현식이 단 하나의 메소드만을 호출하는 경우에 해당 람다 표현식에 불필요한 매개변수를 제거하고 사용할 수 있도록 해줍니다.

메소드 참조를 사용하면 불필요한 매개변수를 제거하고 다음과 같이 '::'기호를 사용하여 표현할 수 있습니다.

문법
클래스 이름 :: 메소드 이름
또는 
참조변수 이름 :: 메소드 이름 

다음 예제는 두 개의 값을 전달받아 제곱 연산을 수행하는 Math 클래스의 클래스 메소드인 pow() 메소드를 호출하는 람다 표현식 입니다.

(base, exponent) -> Math.pow(base, exponent);

위의 예제는 단순히 Math 클래스의 pow() 메소드로 인수로 전달하는 역할만 하므로, 메소드 참조를 사용하여 다음과 같이 간단히 표현할 수 있습니다.

예제

Math :: pow;

또한, 특정 인스턴스의 메소드를 참조할 때에도 참조 변수의 이름을 통해 메소드 참조를 사용할 수 있습니다.

예제

MyClass obj = new MyClass;
Function<String, Boolean>func = (a) -> obj.equal(a);	// 람다 표현식
Funciton<String, Boolean>func = obj :: equals(a);		// 메소드 참조

다음 예제는 람다 표현식과 메소드 참조를 비교하는 예제입니다.


예제


DoubleUnaryOperator oper;

oper = (n) -> Math.abs(n); // 람다 표현식

System.out.println(oper.applyAsDouble(-5));

 
oper = Math::abs; // 메소드 참조

System.out.println(oper.applyAsDouble(-5));

결과

5.0
5.0


생성자 참조

생성자를 호출하는 람다 표현식도 앞서 살펴본 메소드 참조를 이용할 수 있습니다.

즉, 단순히 객체를 생성하고 반환하는 람다 표현식은 생성자 참조로 변환할 수 있습니다.

다음 예제는 단순히 객체를 생성하고 반환하는 람다 표현식 입니다.

예제
(a) -> {return new object(a);}

위의 예제는 단순히 Object 클래스의 인스턴스를 생성하고 반환하기만 하므로, 생성자 참조를 사용하여 다음과 같이 간단히 표현할 수 있습니다.

예제

Object :: new

이때 해당 생성자가 존재하지 않으면 컴파일 시 오류가 발생합니다.

또한, 배열을 생성할 때에도 다음과 같이 생성자 참조를 사용할 수 있습니다.

예제

Function<Integer, double[]>func1 = a -> new double[a]; 	// 람다 표현식

Function<Integer, double[]>func2 = double[]::new;		// 생성자 참조


0개의 댓글