*알림 : *
Effective Java 3판은 Java 9까지 도입된 언어적 기능을 중심으로 서술되어 있습니다. 10버젼 이후의 Java 개발을 하시는 분들은 우회적인 접근법 대신 Java 언어 내 새로 도입된 기능이 더 간결하고 좋을 수 있습니다.해당 포스팅은 SSAFY 내 책읽기 스터디의 활동을 통해 작성된 포스팅입니다.
https://github.com/kjsu0209/JavaBook
https://medium.com/javabook
Java가 람다를 지원하기 이전에, 함수형 패러다임을 사용하고 싶었던 개발자는 추상 메서드를 단 하나만 담은 인터페이스를 사용했다. 특정 함수나 동작을 나타낸다고 하여 함수 객체(function object)라고 불렀는데 JDK1.1에서 익명 클래스(Anonymous class)가 등장하면서 함수 객체를 만드는 주요 수단이 되었다.
예제 1 : 익명 클래스의 인스턴스를 함수 객체로 사용
Collections.sort(words, new Comparator<String>(){
public int compare(String s1, String s2) {
return Integer.compare(s1.length(), s2.length());
}
});
그러나 코드가 너무 길어서 함수형 패러다임을 Java 코딩에 적용하기엔 적합하지 않았다.
Java 8에 와서 추상 메서드를 하나만 담은 인터페이스의 인스턴스를 람다식(lambda expression)을 이용해 간결하게 만들 수 있다.
예제 2 : 익명 클래스 대신 람다를 함수 객체로 사용
Collections.sort(words, (s1,s2)-> Integer.compare(s1.length(), s2.length()));
람다식의 타입은 Comparator, 매개 변수의 타입은 String, 반환타입은 int지만 컴파일러는 타입을 추론하여 결정한다.
예제 3. 람다 대신 비교자 생성 메서드를 사용 (ITEM 43)
Collections.sort(words, comparingInt(String::length));
Enum을 다를 때, 만약 각 상수마다 동작이 다를 때를 대비해서 추상 메서드를 정의하고 각 상수별로 메서드를 재정의 하는 패턴도 람다를 사용하면 다음과 같이 깔끔하게 바뀔 수 있다.
예제 4. 상수별 클래스 몸체와 데이터를 사용한 열거타입(34-6)
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; }
},
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);
}
예제 4-1. 예제4에 람다(함수 객체)를 적용하여 구현
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;
/*
DoubleBinaryOperator는 java.util.function 패키지에 있다.
double 타입 parameter 2개를 받아 double을 리턴하는 인터페이스이다.
*/
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);
}
}
그러나 람다가 만능이지는 않다.
단점
- 람다는 이름이 없고 문서화도 하지 못한다.
- 코드만 보고 동작을 이해할 수 없을 정도로 길거나 복잡하다면, 람다를 쓰지 않는 것이 좋다.
- 람다는 함수형 인터페이스에서만 쓰인다.
- 람다는 추상 클래스의 인스턴스를 만들 수 없으므로, 익명 클래스를 대신 써야 한다.
- 람다는 자기 자신을 참조할 수 없다.
- 람다 안에서 this는 바깥 인스턴스를 의미하지만, 익명 클래스의 this는 익명 클래스의 인스턴스 자기 자신을 가르킨다.
- 람다는 직렬화할 수 없다.
- 람다의 직렬화 형태는 구현이나 가상머신별로 다를 수 있다. 대신 Comparator와 같이 private static nested class를 쓰는 것이 좋다.
'IT > Effective Java' 카테고리의 다른 글
[Effective Java 3/E] ITEM 44. 표준 함수형 인터페이스를 사용하라 (0) | 2021.04.14 |
---|---|
[Effective Java 3/E] ITEM 43. 람다보다는 메서드 참조를 사용하라 (0) | 2021.04.14 |
[Effective Java 3/E] ITEM 41. 정의하려는 것이 타입이라면 마커 인터페이스를 사용하라 (0) | 2021.03.28 |
[Effective Java 3/E] ITEM 40. @Override Annotation을 일관적으로 사용하기 (0) | 2021.03.28 |
[Effective Java 3/E] ITEM 39. 명명 패턴보다 애너테이션을 사용하라 (0) | 2021.03.28 |
댓글