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

가능한 람다를 사용하자!

📌 1. 발표 전 알아야 할 개념

🤔 왜 람다가 중요할까? - 배경에 관하여 자바 8 이전에는 함수형 인터페이스(1개의 추상 메서드를 가진 인터페이스)를 구현할 때 익명 클래스를 주로 사용했다. 간단한 Car 예시를 통해 살펴보자.

public class Car {
    private final String name;
    private final int speed;

    public Car(String name, int speed) {
        this.name = name;
        this.speed = speed;
    }
    // 생략
    @Override
    public String toString() {
        return name + "(" + speed + "km/h)";
    }
}
// 함수형 인터페이스 Comparator<> 사용
Comparator<Car> carComparator = new Comparator<Car>() {
    @Override
    public int compare(Car c1, Car c2) {
        return c1.getSpeed() - c2.getSpeed();
    }
};

익명 클래스는 코드를 장황하게 하고 복잡하게 만든다! 그래서? 자바 8 이후에 람다가 등장했다

📕 2. 람다를 사용하자!

2-1. 람다(Lambda expression)

  • 짧은 코드로 함수를 표현하는 방법

  • 복잡한 익명 클래스를 간단하고 명확한 문법으로 대체

(매개변수) -> {실행 코드}

위의 코드를 바꿔보면,

Comparator<Car> carComparator = (c1, c2) -> c1.getSpeed() - c2.getSpeed();

+) 람다의 모든 매개변수 타입은 생략하자

Collections.sort(words,
    (s1, s2) -> Integer.compare(s1.length(), s2.lengt()));

words의 경우 String, 비교의 경우 int형이지만 컴파일러가 문맥을 파악해 타입 추론을 해준다. 단, 제네릭과 함께 쓰일 때 타입이 모호하거나, 추론이 안되는 경우가 발생할 수 있어 이때는 경고를 보고 타입을 명시해주자.

2-2. 람다 함수 더보기

🫡 람다를 써야 할 때!

  • 의도 표현이 명확할 때

  • 불필요한 코드를 제거할 수 있을 때

  • 익명 클래스 대신 사용

🤔 람다의 단점

  • 람다는 이름이 없다

  • 직접 주석을 달거나 JavaDoc으로 문서화할 수 없다

  • 간결하기에 의도를 파악하기 어려울 수 있다

  • 세 줄이 넘어가면 가독성이 매우 떨어진다

❓3. 익명 클래스가 더 나을 때도 있나요?

3-1. 인스턴스 필드나 상태가 필요한 경우

  • 람다는 상태(필드)를 가질 수 없다

Runnable r = new Runnable() {
    int count = 0; // 필드
    @Override
    public void run() {
        count++;
        System.out.println("Run count: " + count);
    }
};

3-2. this 키워드가 헷갈릴 때

  • (익명 클래스) this는 익명 클래스 자기 자신을 가리킴

  • (람다) this는 자신을 감싸고 있는 외부 클래스를 가리킴

public class Garage {
    void test() {
        Runnable r1 = new Runnable() {
            public void run() {
                System.out.println(this); // 익명 클래스 자기 자신
            }
        };
        // 출력 : item42.Garage$1@3b07d329

        Runnable r2 = () -> {
            System.out.println(this); // Garage 클래스의 인스턴스
        };
        // 출력 : This is Garage

        r1.run();
        r2.run();
    }

    @Override
    public String toString() {
        return "This is Garage";
    }
}

💨 향후 확장 포인트

람다는 이름이 없는 객체이므로 직렬화를 제대로 지원하지 않아, JVM 구현에 따라 동작이 달라질 수 있다. 직렬화가 필요한 상황에는 명시적인 클래스를 사용하자!


🤖 최종 결론

익명 클래스보다는 람다를 사용하자 람다를 통해 함수형 인터페이스의 구현을 간단하게 표현할 수 있다


❗어려웠던 점

  • 용어들이 헷갈려서 하나하나 찾아보면서 이해하는데 시간이 걸렸다다


😶‍🌫️ 느낀점

  • 람다를 잘 활용하지 않았는데, 앞으로 함수형 인터페이스를 구현할 때는 람다를 사용하도록 해야겠다!

Last updated