[Effective Java] 7 - item42 익명 클래스보다는 람다를 사용해라.
함수 객체를 사용하는 과거 객체 지향 디자인 패턴에는 익명 클래스 (item 24) 면 충분했다. 하지만 이 방식은 코드가 너무 길기 때문에, 함수형 프로그래밍에 적합하지 않다.
아래 코드는 정렬을 위한 비교 함수를 익명 클래스로 구현한 예시이다.
Collections.sort(words, new Comparator<String>() {
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
람다식
Java 8부터 함수형 인터페이스의 인스턴스를 람다식을 이용해 만들 수 있게 되었다. 이는 익명 클래스와 개념은 비슷하지만, 코드는 훨씬 간결하고 동작이 명확해진다.
아래 코드는 정렬을 위한 비교 함수를 람다식으로 구현한 예시이다.
Collections.sort(words,
(s1, s2) -> Integer.compare(s1.length(), s2.length()));
람다에서는 컴파일러가 문맥을 살펴 람다, 매개변수, 반환값의 타입을 추론하므로 타입을 명시해야 코드가 더 명확한 경우를 제외하고, 람다의 모든 매개변수 타입은 생략하는 것이 좋다.
자바에서 람다를 지원하게 된 이후로, 기존에는 적합하지 않았던 곳에도 함수 객체를 사용할 수 있게 되었다.
열거 타입에서 메서드의 동작이 상수마다 달라야 하는 경우, 열거 타입에 인스턴스 필드를 두어 구현(item 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);
}
}
...
public static void main(String[] args) {
double x = 10.0;
double y = 5.0;
for (Operation op : Operation.values()) {
System.out.printf("%.1f %s %.1f = %.1f%n", x, op, y, op.apply(x, y));
}
}
람다 식으로 표현했을때 코드가 훨씬 간결해진다고 해서 상수별 클래스 몸체를 쓰지 말아야 하는 것은 아니다.
- 상수별 동작을 간결하게 구현하기 어렵거나, 인스턴스 필드 혹은 메서드를 사용해야만 한다면 상수별 클래스 몸체를 사용하는 것이 좋다.
- 추상 클래스의 인스턴스를 만들 때 람다 사용이 불가능하므로, 익명 클래스를 사용해야 한다.
- 람다는 자신을 참조할 수 없으므로 함수 객체가 자신을 참조해야 한다면(
this
) 익명 클래스를 사용하자.
람다도 익명 클래스처럼 직렬화 형태가 구현별로 다를 수 있으므로, 람다를 직렬화하는 일은 삼가자.
Leave a comment