Skip to content

Latest commit

 

History

History
94 lines (70 loc) · 4.5 KB

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

File metadata and controls

94 lines (70 loc) · 4.5 KB

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

  • 예전에는 자바에서 함수 타입을 표현할 때 추상 메서드를 하나만 담은 인터페이스(드물게는 추상 클래스)를 사용했다.
    • 이런 인터페이스의 인스턴스를 함수 객체라고 한다.
  • JDK 1.1이 등장하면서 함수 객체를 만드는 주요 수단은 익명 클래스가 되었다.
    • 익명 클래스 방식은 코드가 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않았다.
  • 자바 8에 와서 함수형 인터페이스(추상 메서드 하나짜리 인터페이스)들의 인스턴스를 람다식(혹은 람다)을 사용해 만들 수 있게 되었다.

익명 클래스의 인스턴스를 함수 객체로 사용 - 낡은 기법이다!

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()));  

타입을 명시해야 코드가 더 명확할 때만 제외하고는, 람다의 모든 매개변수 타입은 생략하자. 그런 다음 컴파일러가 "타입을 알 수 없다"는 오류를 낼 때만 해당 타입을 명시하면 된다.

람다 자리에 비교자 생성 메서드 사용 - 코드를 더 간결하게 만들 수 있다

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

(자바 8 때 List 인터페이스에 추가된) sort 메서드 이용 - 더욱 짧아진다

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

아이템 34에서는 상수별 클래스 몸체를 구현하는 방식보다는 열거 타입에 인스턴스 필드를 두는 편이 낫다고 했다. 람다를 이용하면 후자의 방식을 쉽게 구현할 수 있다.

상수별 클래스 몸체와 데이터를 사용한 열거 타입

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; } };  
  
    public abstract double apply(double x, double y);
}

함수 객체(람다)를 인스턴스 필드에 저장해 상수별 동작을 구현한 열거 타입

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 DoubleBinaryOperator op;  
      
    Operation(DoubleBinaryOperator op) {  
        this.op = op;  
    }  
      
    public double apply(double x, double y) {  
        return op.applyAsDouble(x, y);  
    }  
}

상수별 클래스 몸체는 더 이상 사용할 이유가 없을까?

람다 기반 Operation 열거 타입을 보면 상수별 클래스 몸체는 더 이상 사용할 이유가 없다고 느낄지 모르지만, 꼭 그렇지는 않다.
상수별 동작을 단 몇 줄로 구현하기 어렵거나, 인스턴스 필드나 메서드를 사용해야만 하는 상황이라면 상수별 클래스 몸체를 사용해야 한다.

  • 이유 1: 메서드나 클래스와 달리, 람다는 이름이 없고 문서화도 못 한다.
  • 이유 2: 열거 타입 생성자에 넘겨지는 인수들의 타입도 컴파일타임에 추론된다. 열거 타입 생성자 안의 람다는 런타임에 만들어지는 열거 타입의 인스턴스 멤버에 접근할 수 없다.

익명 클래스는 언제 사용할까?

이처럼 람다의 시대가 열리면서 익명 클래스는 설 자리가 크게 좁아진 게 사실이다. 하지만 람다로 대체할 수 없는 곳이 있다.

익명 클래스는 함수형 인터페이스가 아닌 타입의 인스턴스를 만들 때 사용하면 된다.

  • 이유: 람다는 함수형 인터페이스에서만 쓰인다.
  • 예: 추상 클래스의 인스턴스를 만들 때, 추상 메서드가 여러 개인 인터페이스의 인스턴스를 만들 때

함수 객체가 자신을 참조해야 한다면 반드시 익명 클래스를 써야 한다.

  • 이유: 람다는 자신을 참조할 수 없다.
    • 람다에서의 this 키워드는 바깥 인스턴스를 가리킨다. 반면 익명 클래스에서의 this는 익명 클래스의 인스턴스 자신을 가리킨다.