익명 클래스는 옛날 수단이 되었다.

 

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

이 코드에서 Comparator 인터페이스가 정렬을 담당하는 추상 전략을 뜻하며,

문자열을 정렬하는 구체적인 전략을 익명 클래스로 구현했다.

 

하지만 익명 클래스 방식은 코드가 너무 길기 때문에 자바는 함수형 프로그래밍에 적합하지 않았다.

 

지금은 함수형 인터페이스라 부르는 이 인터페이스들의 인스턴스를 람다식을 사용해 만들 수 있다.

 

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

여기서 람다, 매개변수(s1, s2) 반환값의 타입은 각각 Comparator<String> , String, int지만 코드에서는 언급이 없다.

우리 대신 컴파일러가 문맥을 살펴 타입을 추론해 준것이다.

 

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

 

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

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

여기서 람다식의 콜론 두개 (::)는 메소드 참조 표현식이며 파라미터를 중복해서 사용하고 싶지 않을 때 사용한다.

쉬운 예시로는

list.forEach(x -> System.out.println(x));

이 표현식은 list에 있는 하나씩 출력하는 표현식인데

list.forEach(System.out::println);

다음 처럼 바꾸면 System 클래스가 가진 println메소드를 forEach에게 전달해준 것이다.

우리는 람다를 사용하면 아이템 34에서 했던 열거타입 형태도 간단하게 바꿀 수 있다.

 

 

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

import java.util.function.DoubleBinaryOperator;

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 타입 결과를 돌려준다.

람다를 사용하면 전부 편하게 바꿀수 있을거라고 생각이 들지만 단점이 있다.

  • 메소드나 클래스와 달리 람다는 이름이 없고 문서화도 못한다
  • 따라서 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지만 람다를 쓰면 안된다.
  • 한줄 일 때 가장 좋고 길어야 세 줄 안에 끝내는 것이 좋다.
  • 람다는 자기 자신을 참조할 수 없다(this가 안된다.)
  • 람다를 직렬화 하는 일은 극히 삼가야 한다.
  • 직렬화해야만 하는 함수 객체가 있다면 private 정적 중첩 클래스 인스턴스를 사용하자

+ Recent posts