[JAVA] 람다(Lambda)

2022. 9. 15. 20:52

람다식

람다식은 함수를 간단한 식(expression)으로 표현하고 람다식을 익명 함수(anonymous function)이라고도 한다.

int max(int a, int b){
    return a > b ? a : b;
}

일반적으로 정의해서 사용하는 함수는 위와 같다.  함수를 람다식으로 간단하게 표현할 수 있고 그 덕분에 가독성이 높아지고 생산성이 높아진다.

(a, b) -> a > b ? a : b

 


람다식으로 표현하기

앞에서 본 max 함수를 람다식으로 표현하는 방법을 알아보자

 

1. 메서드 이름과 반환 타입을 제거하고 '->'를 {} 앞에 추가한다.

(int a, int b) -> {
    return a > b ? a : b;
}

2. return 값이 있는 경우 return을 생략하여 식으로 표현할 수 있고 식으로 표현되는 경우 세미콜론(;)을 붙이지 않는다.

(int a, int b) -> a > b ? a : b

3. 람다식의 매개변수 타입이 추론 가능하면 생략할 수 있다.

(a, b) -> a > b ? a : b

※ 매개변수가 하나인 경우 괄호는 생략 가능하다.

(a) -> a * a   // a -> a * a

 

자바에서 메서드는 클래스 내에 포함되어 있어야 한다.

이제 이렇게 만든 람다식을 사용해야 하는데 람다식은 어떤 클래스에 포함이 되어있는 것이고 어떤 객체를 생성해야 하는 것일까

메서드라고 생각했던 람다식은 익명 객체이다.

new Object() {
    int max(int a, int b) {
        return a > b ? a : b;
    }
};

max 메서드를 사용하려면 참조 변수가 필요하고 이 문제를 해결해주는 것이 함수형 인터페이스다.


함수형 인터페이스

함수형 인터페이스는 하나의 추상 메서드만 선언된 인터페이스다.

함수형 인터페이스를 만들고 익명 클래스로 함수형 인터페이스의 메서드를 구현한다면 람다식을 사용할 수 있다.

@FunctionalInterface
interface MyFunction{
    public abstract int max(int a,int b);
}

public class LambdaTest {
    public static void main(String[] args) {
        //익명 클래스
        MyFunction f1 = new MyFunction() {
            @Override
            public int max(int a, int b) {
                return a > b ? a : b;
            }
        };
        //람다식
        MyFunction f2 = (a,b) -> a > b ? a : b;
        int max = f1.max(10, 100);
        System.out.println(max);
        max = f2.max(100,200);
        System.out.println(max);
    }
}

 

java.util.function 패키지에는 자주 쓰이는 형태의 메서드를 함수형 인터페이스로 정의해놨다. 

  • Supplier<T>
  • Consumer<T>
  • Function<T,R>
  • Predicate<T>

Supplier<T>: 매개변수는 없고 반환 값만 있는 함수형 인터페이스

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

Supplier<String> s = () -> "Hello";
System.out.println(s.get()); //hello

Consumer<T>: 매개 변수만 있고 반환 값이 없는 함수형 인터페이스

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

Consumer<String> c = (str) -> System.out.println("hello " + str);
c.accept("kim"); //hello kim

Function<T,R> : 매개변수, 반환 값이 있는 함수형 인터페이스

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}

Function<Integer,Integer> f = i -> i*10;
System.out.println(f.apply(10)); // 100

 

Predicate<T>: 매개변수가 있고 반환형이 boolean인 함수형 인터페이스

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

Predicate<Integer> p = i -> i % 2 == 0;
System.out.println(p.test(20)); //true

메서드 참조(method reference)

메서드 참조는 하나의 메서드만 호출하는 람다식을 더 간단하게 표현할 수 있는 방법을 제공한다.

Function<String,Integer> f = (String s) -> Integer.parseInt(s);
System.out.println(f.apply("100"));

 

 

문자열을 정수로 바꿔주는 람다식인데 메서드 참조로 람다식의 일부를 생략해서 다음과 같이 만들 수 있다.

Function<String,Integer> f = Integer::parseInt;
System.out.println(f.apply("100"));

컴파일러는 함수형 인터페이스의 메서드의 선언부와 제네릭 타입을 통해 알 수 있기 때문에 생략이 가능한 것이다.

 

 

BELATED ARTICLES

more