자바가 람다를 지원하면서 API를 작성하는 모범 사례도 크게 바뀌었다.
예) 상위 클래스의 기본 메서드를 재정의해 원하는 동작을 구현하는 템플릿 메서드 패턴의 매력이 크게 줄었다.
이를 대체하는 현대적인 해법
→ 같은 효과의 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 것이다.
→ 일반화해서 말하면, 함수 객체를 매개변수로 받는 생성자와 메서드를 더 많이 만들어야 한다.
LinkedHashMap을 생각해보자. 이 클래스의 protected 메서드인 removeEldestEntry를 재정의하면 캐시로 사용할 수 있다.
맵에 새로운 키를 추가하는 put 메서드는 이 메서드를 호출하여 true가 반환되면 맵에서 가장 오래된 원소를 제거한다.
예) removeEldestEntry를 다음처럼 재정의하면 맵에 원소가 100개가 될 때까지 커지다가, 그 이상이 되면 새로운 키가 더해질 때마다 가장 오래된 원소를 하나씩 제거한다.
즉, 가장 최근 원소 100개를 유지한다.
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size() > 100;
}
잘 동작하지만 람다를 사용하면 훨씬 잘 해낼 수 있다.
LinkedHashMap을 오늘날 다시 구현한다면 함수 객체를 받는 정적 팩터리나 생성자를 제공했을 것이다.
코드 44-1 불필요한 함수형 인터페이스 - 대신 표준 함수형 인터페이스를 사용하라
@FunctionaInterface EldestEntryRemovalFunction<K,V> {
boolean remove(Map<K,V> map, Map.Entry<K,V> eldest);
}
이 인터페이스도 잘 동작하기는 하지만, 굳이 사용할 이유는 없다.
Because __ 자바 표준 라이브에 이미 같은 모양의 인터페이스가 준비되어 있다.
java.util.function 패키지를 보면 다양한 용도의 표준 함수형 인터페이스가 담겨 있다.
필요한 용도에 맞는 게 있다면, 직접 구현하지 말고 표준 함수형 인터페이스를 활용하라.
예컨대 Predicate 인터페이스는 프레디키트(predicate)들을 조합하는 메서드를 제공한다.
앞의 LinkedHashMap 예에서는 직접 만든 EldestEntryRemovalFunction 대신 표준 인터페이스인
BiPredicate<Map<K,V>>, Map.Entry<K,V>을 사용할 수 있다.
직접 만든 함수형 인터페이스에은 항상 @FunctionalInterface 애너테이션을 사용하자