item42


익명 클래스보다는 람다를 사용하라

익명 클래스

익명 클래스는 내부 클래스 일종으로 단어 그대로 이름이 없는 클래스를 말한다.

public interface CoffeeMachine {
    void makeCoffee();
}

public class Cafe {

    public static void main(String[] args) {
        CoffeeMachine coffeeMachine = new CoffeeMachine() {
            @Override
            public void makeCoffee() {
                System.out.println("커피를 내립니다.");
            }
        };
    }
}

익명 클래스와 함수 객체

자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스를 사용했다. 이런 인터페이스의 인스턴스를 함수객체라고 하여, 특정 함수나 동작을 나타내는 데 썼다. 이러한 함수 객체를 만드는 수단은 익명 클래스가 되었다.

        List<String> words = List.of("1", "2");
        Collections.sort(words, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });

하지만 익명 클래스 방식은 위 코드처럼 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않았다. 자바8 부터는 자바가 함수형 프로그래밍에도 적합한 언어로 다시 태어났는데 바로 람다식 덕분이었다.

람다식

람다는 함수나 익명 클래스와 개념은 비슷하지만 코드는 훨씬 간결하다.

        List<String> words = List.of("1", "2");
        Collections.sort(words, (o1, o2) -> o1.compareTo(o2));

여기서 람다, 매개변수, 반환값의 타입은 코드에서 언급이 없다. 우리 대신 컴파일러가 문맥을 살펴 타입을 추론해준 것이다. 상황에 따라 컴파일러가 타입을 결정하지 못하여 프로그래머가 직접 명시해야 할 수도 있지만, 타입 추론 규칙은 너무 복잡하기 때문에 타입을 명시해야 코드가 더 명확할 때만 제외하고는, 람다의 모든 매개변수 타입은 생략하자. 그런 다음 컴파일러가 타입을 알 수 없다는 오류를 낼 때만 정의하자.

<aside> 💡

제네릭의 로 타입을 쓰지 말라고 이전 아이템에서 나왔었다. 람다에서는 타입이 정말 중요하다. 컴파일러가 타입을 추론하는 데 필요한 타입 정보 대부분을 제네릭에서 얻기 때문이다. 우리가 이 정보를 제공하지 않으면 컴파일러는 람다의 타입을 추론할 수 없게 되어, 결국 우리가 일일이 명시해야 한다. 위 코드에서 words 의 타입이 List<String> 가 아니라 List 였으면 에러가 났을 것이다.

</aside>