[아이템 42] 익명 클래스보다는 람다를 사용하라

Jimin Lim·2023년 6월 27일
0

Effective Java

목록 보기
26/38
post-thumbnail
post-custom-banner

아이템 42

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

✅ 람다 예시

익명 클래스

Collections.sort(words, new Comparator<String>() {
    public int compare(String s1, String s2) {
        return Integer.compare(s1.length(), s2.length());
    }
});

람다

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

위 코드는 추상 메서드(compare) 하나만 담은 Comparator 클래스를 익명 클래스로 구현하고 있다. 이 방식은 코드가 너무 길어 함수형 프로그래밍에 적합하지 않았다.
아래 코드는 자질구레한 코드들이 사라지고 어떤 동작을 하는지 명확히 드러내고 있다. 특히 타입 추론을 이용해 간결하게 작성하고 있는데, 타입을 명시해야 코드가 더 명확할 때만 제외하고는 매개변수 타입은 생략하는 것을 추천한다.

비교자 생성 메서드를 사용해 간결하게 만들 수 있으며,

Collections.sort(words, comparingInt(String::length));

List 인터페이스에 추가된 sort 메서드를 이용해 더 간결하게 표현할 수 있다.

words.sort(comparingInt(String::length));

✅ enum에 람다 적용

public enum Operation {
    PLUS("+") {public double apply(double x, double y) {return x + y;}},
    MINUS("-") {public double apply(double x, double y) {return x - y;}},
    TIMES("*") {public double apply(double x, double y) {return x * y;}},
    DIVIDE("/") {public double apply(double x, double y) {return x / y;}};
	
	private final String symbol;

    Operation(String symbol) { this.symbol = symbol; }

    @Override public String toString() { return symbol; }

	// 추상 메서드
	public abstract double apply(double x, double y);
}

각 enum에 apply 함수를 구현한 예제(아이템 34)다. 이때 상수별 클래스 몸체를 구현하기보다는 인스턴스 필드를 두는 것이 낫다고 하였는데, 후자의 방식으로 람다를 구현할 수 있다.

public enum Operation {
    PLUS("+", (x, y) -> x+y);
    MINUS("-", (x,y) -> x-y);
    TIMES("*", (x,y) -> x*y);
    DIVIDE("/", (x,y) -> x / y);
    
    private final String symbol;
    private final DoubleBinaryOperator op;
    
    Operation(String symbol, DoubleBinaryOperator op) { 
        this.symbol = symbol;
        this.op = op;
    }
    
    @Override
    public String toString() {
        return symbol;
    }
    
    public double apply(double x, double y) {
        return op.applyAsDouble(x, y);
    }
}
  • DoubleBinaryOperator: double 타입 2개받아 double 타입 반환하는 함수 인터페이스 (java.util.function에 존재)

람다는 이름이 없고 문서화를 할 수 없기에 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 지양하는 것이 좋다. (1~3 줄 안에 끝내는 것이 좋다)

enum 타입에서 사용하는 람다의 인수는 컴파일 시점 타입추론이 되므로 필드에 접근할 수 없다. 즉, 필드나 메서드를 사용해야할 일이 있다면 상수별 클래스 몸체를 사용해야 한다.

✅ 익명클래스를 사용하는 경우

1. 추상 클래스의 인스턴스를 만들 때 익명 클래스

abstract class AbstractClass {
    public abstract void abstractMethod();
}
 AbstractClass abstractInstance = new AbstractClass() {
            @Override
            public void abstractMethod() {
                System.out.println("Implemented abstractMethod");
            }
        };

추상 클래스는 멤버 변수, 메서드를 가지는데 람다식은 변수에 접근할 수 없으므로 람다로는 사용할 수 없다.

2. 추상 메서드가 여러 개인 인터페이스의 인스턴스를 만들 때 익명 클래스
마찬가지로 함수형 인터페이스(추상 메서드 하나)가 아닌 인터페이스를 람다로 생성할 수 없으므로 익명클래스 사용

3. 자신을 참조해야 할 경우 익명 클래스
람다의 this는 바깥 인스턴스를 가리키고, 익명 클래스의 this는 자신을 참조하는 것이다.

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️
post-custom-banner

0개의 댓글