이펙티브 자바, 쉽게 정리하기 - item 42. 익명 클래스보다는 람다를 사용하라
메서드 파라미터로 함수 객체를 받는 경우: 람다 미사용
@Test
public void sortTest1() {
System.out.println("beforeSort: " + words.toString());
Collections.sort(words, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return Integer.compare(o1.length(), o2.length());
}
});
System.out.println("afterSort: " + words.toString());
}
- 기존에는 위와 같이 익명 클래스를 이용해 처리했다.
메서드 파라미터로 함수 객체를 받는 경우: 람다 사용
@Test
public void sortTest1() {
System.out.println("beforeSort: " + words.toString());
Collections.sort(words, (o1, o2) -> Integer.compare(o1.length(), o2.length()));
System.out.println("afterSort: " + words.toString());
}
Comparator
타입은 추상메서드 하나만 구현하면 되기 때문에 람다로 대체할 수 있다.- 타입을 명시해야 코드가 더 명확할 때만 제외하고는 람다의 모든 매개변수 타입을 생략하자
- 그래야 코드가 더 간단해진다. 컴파일러가 타입을 알 수 없다는 오류를 내면 그 때 타입을 적어도 된다.
제네릭을 잘 써주는 경우엔 컴파일러의 람다 타입 추론에 더욱 유리해지니 제네릭을 잘 써주자. 잘 수행될 수 있는 코드도 Raw 타입을 활용하면 에러가 날 수 있으니 주의하자.
메서드 파라미터로 함수 객체를 받는 경우: 람다 + 비교자 생성 메서드 활용
@Test
public void sortTest1() {
System.out.println("beforeSort: " + words.toString());
Collections.sort(words, Comparator.comparingInt(String::length));
System.out.println("afterSort: " + words.toString());
}
@Test
public void sortTest2() {
System.out.println("beforeSort: " + words.toString());
words.sort(Comparator.comparingInt(String::length));
System.out.println("afterSort: " + words.toString());
}
이전보다도 훨씬 간결해졌다. 처음 익명클래스를 사용할 때와 비교하면 정말 정말 간결해졌다.
람다 활용하기: enum Operation
활용 전
enum Operation {
PLUS("+") {
@Override
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
@Override
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
@Override
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);
}
활용 후
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 BinaryOperator<Double> op;
Operation(String symbol, BinaryOperator<Double> op) {
this.symbol = symbol;
this.op = op;
}
@Override
public String toString() {
return symbol;
}
public double apply(double x, double y) {
return op.apply(x, y);
}
}
@Test
public void opTest() {
double x = 7.4;
double y = 6.1;
System.out.println("x = " + x);
System.out.println("y = " + y);
for (Operation op : Operation.values()) {
double apply = op.apply(x, y);
System.out.println("apply [" + op.name() + "] = " + apply);
}
}
- 자바에서 기본으로 제공하는 함수 인터페이스 중 하나인
BinaryOperator
를 통해 코드를 개선했다. - 훨씬 더 관심사의 분리가 잘 이루어져서, 어떤 연산을 하는지 살펴보기 훨씬 쉬워졌다.
단, 람다는 이름도 없고 문서화도 못하기 때문에 코드 자체로 동작이 명확히 설명되지 않거나 코드 줄 수가 많아지면 람다를 쓰지 않는 것이 좋다.
람다 주의점
this
키워드
- 람다의
this
키워드는 바깥을 가리키므로 주의해야 한다. - 반면 익명 클래스의
this
키워드는 인스턴스 자신을 가리키므로 함수 객체가 자신을 참조해야 한다면 익명 클래스를 사용하자.
직렬화
- 람다는 가상머신별로 직렬화 형태가 다를 수 있기 때문에 주의해야 한다.
핵심 요약
- 익명 클래스는 (함수형 인터페이스가 아닌) 타입의 인스턴스를 만들 때만 사용하자.
반응형
'Java > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바, 쉽게 정리하기 - item 45. 스트림은 주의해서 사용하라 (0) | 2023.03.29 |
---|---|
이펙티브 자바, 쉽게 정리하기 - item 43. 람다보다는 메서드 참조를 사용하라 (2) | 2022.06.13 |
이펙티브 자바, 쉽게 정리하기 - item 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 (0) | 2022.05.24 |
이펙티브 자바, 쉽게 정리하기 - item 40. @Override 애너테이션을 일관되게 사용하라 (0) | 2022.05.24 |
이펙티브 자바, 쉽게 정리하기 - item 39. 명명 패턴보다 애너테이션을 사용하라 (0) | 2022.05.24 |