자바 (ref. 자바의정석)

람다식(Lambda expression) - JAVA

쿠쿠s 2022. 3. 17. 14:25

 

람다식이란?

람다식은 메서드를 하나의 식으로 표현한 것입니다. 메서드를 간략하면서도 명확한 식으로 표현할 수 있게 해주며, 메서드의 이름과 반환값이 없어지므로 '익명함수(anonymous function)' 이라고도 합니다.

 

람다식은 '익명 함수' 답게 메서드에서 이름과 반환타입을 제거하고 매개변수 선언부와 몸통{ }  사이에 ' -> ' 를 추가합니다.

//기존방식
반환타입 메서드이름(매개변수 선언) {
      문장들
}


//람다사용
(매개변수 선언) -> { 문장들 }

 

 

람다식의 장단점

장점

1. 코드를 간결하고 명확하게 만들 수 있다.

2. 함수를 만드는 과정이 없어 생산성이 높아진다.

3. 다중 cpu를 활용하는 형태로 구현되어 병렬 프로그래밍에 유리

 

단점

1. 남발하여 사용할 경우 가독성이 오히려 떨어짐

2. 람다를 사용하면서 만든 익명함수는 재사용이 불가능하다.

3. 디버깅이 어렵다.

 

 


 

함수형 인터페이스 (Functional Interface)

람다식을 다루기 위한 인터페이스를 '함수형 인터페이스' 라 하며 이는 오직 하나의 추상 메서드만 정의되어 있어야 한다는 제약이 있다습니다. 왜냐하면 그래야 람다식과 인터페이스의 메서드가 1:1로 연결될 수 있기 때문입니다. 

 

 

기존에는 아래와 같이 인터페이스 메서드를 하나 구현하는데에도 코드를 복잡하세 구현을 해야 했습니다.

public class Example {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            list.add((int) (Math.random() * 10) + 1);
        }

        Collections.sort(list, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        
        System.out.println(list);
    }
}

 

하지만 람다식을 사용하여 아래와 같이 간단히 처리할 수 있습니다.

public class Example {

    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            list.add((int) (Math.random() * 10) + 1);
        }

        Collections.sort(list, (o1, o2) -> o1 - o2);

        System.out.println(list);
    }
}

 

 

람다식의 타입과 형변환

 

함수형 인터페이스로 람다식을 참조할 수 있는데 람다식의 타입이 함수형 인터페이스의 타입과 일치하는 것은 아니다. 람다식은 익명 객체이고 익명 객체는 타입이 없기 때문입니다. 정확히는 타입은 있지만 컴파일러가 임의로 이름을 정하기 때문에 알 수는 없습니다. 그래서 형변환이 필요합니다.

 

@FunctionalInterface
interface exFunction {
    void example();
}

public class Example {

    public static void main(String[] args) {
        exFunction f = (exFunction) (() -> {}); //exFunction 생략 가능
        
        //람다식은 Object 형변환이 안된다.
        Object obj = (Object) (() -> {});
        System.out.println(() -> {});
    }
}

 

람다식은 인터페이스를 구현한 클래스의 객체와 동일하기 때문에 (exFunction) 형변환을 허용하고, 생략이 가능하다. 람다식은 이름이 없을 뿐 분명 객체이지만 Object 타입으로 형변환을 할 수 없다. 람다식은 오로지 함수형 인터페이스로만 형변환이 가능합니다.

 

 

 


 

 

java.util.function 패키지

java.util.function 패키지에 일반적으로 자주 쓰이는 형식의 메서드를 함수형 인터페이스로 미리 정의해 놓았다. 이 패키지의 인터페이스를 활용하면 재사용성이나 유지보수 측면에서도 활용도가 좋다.

 

함수형 인터페이스 메서드 설명
java.lang.Runnable void run() 매개변수 x, 반환값 x
Supplier<T> T get() --> T 매개변수 x, 반환값 o
Consumer<T> T --> void accept(T t) Supplier와 반대로 매개변수 o, 반환값 x
Function<T, R> T --> R apply(T t) --> R 일반적인 함수. 하나의 매개변수를 받아서 결과를 반환
Predicate<T> T --> boolean test(T t) --> boolean 조건식을 표현하는데 사용된다.
매개변수는 하나, 반환 타입은 boolean

[참고] 타입 문자 'T' 는 'Type'  , 'R' 은 'Return Type' 이다.