Skip to content

Latest commit

 

History

History
151 lines (108 loc) · 4.46 KB

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

File metadata and controls

151 lines (108 loc) · 4.46 KB

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

  • 예전 자바는 함수 타입을 표현할때 추상메드를 하나만 담은 인터페이스를 사용했다. 이런 인터페이스의 인스턴스를 함수객체(function object)라고함

낡은 기법

  • 익명클래스의 인스턴스를 함수 객체로 사용하는 방식
Collections.sort(words, new Comparator<String>() {
          public int compare(String s1, String s2) {
            return Integer.compare(s1.length(), s2.length());
          }
});
  • 코드가 너무 길다.

람다식 (개선ver#1)

Collections.sort(words,
                (s1, s2) -> Integer.compare(s1.length(), s2.length()));
  • 위 익명 클래스를 람다식으로 바꾸면 훨씬 간결해진다.
  • 람다, 매개변수(s1,s2), 반환값의 타입은 컴파일러가 문맥을 살펴 타입을 추론해준다.

타입을 명시해야 코드가 더 명확할 때 제외하고는, 람다의 모든 매개변수 타입은 생략하자.

  • 상황에 따라 컴파일러가 타입을 컴파일러가 결정 못할때만 직접 명시
  • 컴파일러가 타입을 추론하는데 필요한 타입 정보 대부분을 제네릭에서 얻기 때문에 람다와 쓸때 제네릭은 중요하다.

비교자 생성 메서드

개선ver#2

// 람다 자리에 비교자 생성 메서드(메서드 참조와 함께)를 사용
Collections.sort(words, comparingInt(String::length)
  • 람다 자리에 비교자 생성 메서드를 사용하면 코드를 더 간결하게 만들 수 있다.

개선ver#3

// 비교자 생성 메서드와 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;
        }
    },
    DIVDE("/") {
        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);
}

람다 사용 ver

// 함수 객체(람다)를 인스턴스 필드에 저장해 상수별 동작을 구현한 열거 타입
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);
    }

    // 아이템 34의 메인 메서드 (215쪽)
    public static void main(String[] args) {
        double x = Double.parseDouble(args[0]);
        double y = Double.parseDouble(args[1]);
        for (Operation op : Operation.values())
            System.out.printf("%f %s %f = %f%n",
                    x, op, y, op.apply(x, y));
    }
}

주의사항 (아래 같은 경우는 상수별 클래스 몸체 사용)

  • 만약 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 말아야한다.
  • 열거 타입 생성자 안의 람다는 열거 타입의 인스턴스 필드나 메서드에 접근할 수 없다.
    • 열거 타입 생성자에 넘겨지는 인수들의 타입은 컴파일 타임에 추론되는데 인스턴스는 런타임에 만들어지기 때문이다.

람다로 대체할 수 없는 곳

추상 클래스의 인스턴스를 만들 때는 익명 클래스 써야함.

추상 메서드가 여러 개인 인터페이스의 인스턴스 만들때는 익명 클래스 써야함

람다는 자신을 참조할 수 없다.

  • 람다에서의 this키워드는 바깥 인스턴스를 가리킨다.
  • 익명 클래스에서의 this 키워드는 익명 클래스 인스턴스 자신을 가리킴

익명 클래스는 함수형 인터페이스가 아닌 타입의 인스턴스를 만들 떄만 사용하라