과거에는 특정한 임의의 클래스를 설계해서 주입해야 하는 경우 익명 클래스를 사용할 수 밖에 없었다.
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
}
sort는 Comparator 타입을 입력받고 직접 비교 로직을 구현함으로써 컬렉션을 커스텀 sort 가능해진다.
그러나 java 8 이후 lambda 를 지원하면서 함수형 인터페이스의 경우 lambda로 그 동작을 대체할 수 있다.
함수형 인터페이스란 하나의 클래스의 하나의 동장 메서드만 정의된 것을 의미한다. 이 경우 lambda로 대신할 수 있다.
Comparator 타입의 경우 compare 메서드만 제공하기 때문에 lambda로 이를 충분히 대신 할 수 있다.
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
comparingInt와 메서드 참조를 이용하면 더욱 간결하게 작성할 수 있다.
interface OperationFunction {
int calculate(int a, int b);
}
enum Operation {
PLUS("+", (a, b) -> a + b),
MINUS("-", (a, b) -> a - b),
MULTIPLY("*", (a, b) -> a * b),
DIVIDE("/", (a, b) -> a / b);
private final String symbol;
private final OperationFunction function;
Operation(String symbol, OperationFunction function) {
this.symbol = symbol;
this.function = function;
}
public int calculate(int a, int b) {
return function.calculate(a, b);
}
@Override
public String toString() {
return "Operation{" +
"symbol='" + symbol + '\'' +
", function=" + function +
'}';
}
}
책에서는 abstract를 이용한 방식보다 조금 더 모던한 방식이라 한다. 생성자 주입을 통해 함수형 인터페이스를 주입하고 람다로 정의하는 방법이다. 물론 확장성에서는 enum 자체를 인터페이스 타입으로 지정하고 익명 클래스를 활용하는 방법이 코드 수정이 없기 때문에 조금 더 효과적이라 생각하는데 취향 차이인 것 같다.
여러 동작을 정의해야 하는 경우 => 이 경우는 람다 자체를 사용 불가능하다. 보통 이 경우라면 콜백을 정의하는 경우인데 아마 eventListener 같은 경우에 해당할 것 같다.
동작이 복잡한 경우 => 동작이 복잡하면 람다를 사용할 때 오히려 코드의 가독성이 떨어진다. 책에서는 3줄 안에 코드를 끝내라고 말한다. 나는 3줄도 길다. 2줄 안에는 끝나야 한다고 생각한다.