[Java] 17. Lambda Expression(람다식)


람다식이란 함수(메서드)를 간단한 식(expression)으로 표현하는 방법을 의미한다. 함수형언어에서부터 나온 것이다.



1. 람다식(Lambda Expression)

자바는 JDK1.8에 람다식(lambda expression)이 등장했다. 그래서 함수형언어가 기반으로 함수형프로그래밍이 나왔지만 자바에서 람다식을 지원함으로써 객체지향언어와 동시에 함수형언어가 되었다.

1-1. 람다식 특징

람다식은 자바 8부터 도입된 함수형 프로그래밍의 핵심 요소 중 하나이다. 람다식의 주요 특징은 아래와 같다.

  1. 간결성: 람다식은 매우 간결하고 직관적인 문법을 가지고 있어 코드의 길이를 크게 줄여줍니다. 특히, 간단한 작업을 수행하는 함수를 간결하게 표현할 수 있습니다.

  2. 익명 함수: 이름이 없는 함수로, 메서드와 같이 독립적으로 사용할 수 있는 코드 블록입니다. 메서드처럼 호출할 필요 없이 바로 사용할 수 있습니다.

  3. 함수형 프로그래밍 지원: 람다식은 함수형 프로그래밍의 핵심적인 요소로, 함수를 일급 객체로 취급하여 변수에 할당하고 전달할 수 있습니다.

  4. 함수형 인터페이스 지원: 람다식은 함수형 인터페이스에 사용됩니다. 함수형 인터페이스는 딱 하나의 추상 메서드를 가진 인터페이스이며, 람다식은 이를 구현하여 사용됩니다.

  5. 스트림 API와의 호환성: 람다식은 자바의 스트림 API와 함께 사용되어 데이터를 처리하고 조작하는 데 매우 효과적입니다. 스트림 API에서 람다식을 이용하여 데이터를 다루는 것이 가능합니다.

  6. 병렬 프로그래밍 지원: 병렬 처리를 위해 람다식이 적합합니다. 간단하게 병렬 실행을 할 수 있고, 병렬 프로그래밍을 위한 기능을 제공합니다.

  7. 클로저: 람다식은 자신을 포함하는 범위에 있는 변수를 캡처할 수 있습니다. 이러한 능력을 클로저라고 하며, 외부 범위의 변수를 람다식 내부에서 사용할 수 있게 합니다.



1-2. 기존 메서드를 람다식 표현

람다식이란 함수(메서드)를 간단한 식(expression)으로 표현한 것이다. 람다식은 함수를 간략하면서도 명확화게 표현할 수 있으며, 메서드의 이름과 반환값이 없어지므로 람다식을 익명함수(anonymous function)라고도 한다.

메서드

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

람다식

(a, b) -> a > b ? a:b
//익명 클래스(익명 객체)
Object obj = new Object() {
    int max(int a, int b) {
        return a > b ? a:b;
    }
};

//int ret = obj.max(31, 55);//에러발생!

참조변수 obj 에는 max()라는 메서드가 없기에 에러가 발생한다. 그래서 필요한게 함수형 인터페이스이다.



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

함수형 인터페이스 선언 - 단 하나의 추상 메서드를 가져야만함

@FunctionalInterface    //함수형 인터페이스에는 애너테이션을 명시적으로 선언시 컴파일 체크, 단 하나의 추상 메서드를 가져야만함
public interface ExMyFunction {
    public abstract int max(int a, int b);
}

함수형 인터페이스 사용

ExMyFunction fn = new ExMyFunction() {
    @Override
    public int max(int a, int b) {
        return a > b ? a:b;
    }
};

int ret = fn.max(31, 55);

함수형 인터페이스 fn 에는 ExMyFunction 인터페이스 내에 추상 메서드 max()가 있기 때문에
익명 클래스 내에 max()메서드가 구현체이기에 정상적으로 호출된다.


함수형 인터페이스로 람다식 사용

ExMyFunction lambFn = (a, b) -> a > b ? a : b;
ret = lambFn.max(31, 55);  //실제로는 람다식이 호출됨

람다식(익명객체)를 다루기 위해 참조변수의 타입은 함수형 인터페이스로 해야 한다.



3. 함수형 인터페이스 람다식 예제

3-1. Comparator 함수형 인터페이스로 보는 예제

public class ExCollections {

    public static void main(String[] args) {

        List<String> sortedList1 = Arrays.asList("gsf", "abc", "htw", "asd", "bas", "cas");
        List<String> sortedList2 = Arrays.asList("gsf", "abc", "htw", "asd", "bas", "cas");

        //1. 익명 객체 방법
        Collections.sort(sortedList1, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                return s2.compareTo(s1);
            }
        });
        System.out.println("익명 객체 방법 sort = " + sortedList1);


        //2. 람다식 방법
        Collections.sort(sortedList2, (s1, s2) -> s2.compareTo(s1) );
        System.out.println("람다식 방법 sort = " + sortedList2);
    }
}
익명 객체 방법 sort = [htw, gsf, cas, bas, asd, abc]
람다식 방법 sort = [htw, gsf, cas, bas, asd, abc]

Comparator 함수형 인터페이스

@FunctionalInterface
interface Comparator<T> {
    int compare(T o1, T o2);
}



3-2. 기존메서드 람다식으로 변경 예제

기존 메서드

public class Main {
    static int max(int a, int b) {
        return a > b ? a : b;
    }

    public static void main(String[] args) {
        int result = max(10, 20);
        System.out.println("Max value is: " + result);
    }
}


람다식

public class Main {
    public static void main(String[] args) {
        NumberOperator numOp = new NumberOperator() {
            @Override
            public int max(int a, int b) {
                return a > b ? a : b;
            }
        };

        int result = numOp.max(10, 20);
        System.out.println("Max value is: " + result);
    }
}
@FunctionalInterface
public interface NumberOperator {
    public abstract int max(int a, int b);
}



3-3. 함수형 인터페이스 예제

FunctionalInterface 와 매개변수와 반화타입은 동일해야한다.

@FunctionalInterface
interface MyViewFunction {
    void display();
}

public class ExFunctionalInterface {

    public static void main(String[] args) {

        MyViewFunction v1 = ()-> System.out.println("# display() - 1");


        MyViewFunction v2 = new MyViewFunction() {
            @Override
            public void display() {
                System.out.println("# display() - 2");
            }
        };

        MyViewFunction v3 = getMyViewFunction();

        //각 객체 호출
        v1.display();
        v2.display();
        v3.display();
    }

    public static MyViewFunction getMyViewFunction() {
        return ()-> System.out.println("# display() - 3");
    }
}
# display() - 1
# display() - 2
# display() - 3




[출처]

  • 자바의정석 (저자: 남궁성)