[아이템 44] 표준 함수형 인터페이스를 사용하라

Jimin Lim·2023년 6월 28일
0

Effective Java

목록 보기
28/38
post-thumbnail

아이템 44

표준 함수형 인터페이스를 사용하라

템플릿 메서드 패턴(상위 클래스의 기본 메서드 재정의)은 같은 효과의 함수 객체를 받는 정적 팩터리나 생성자를 제공하는 방법으로 대체될 수 있다. 이때 함수형 매개변수 타입을 올바르게 선택해야 한다.

✅ LinkedHashMap 예시

LinkedHashMap 클래스의 protected 메서드인 removeEldestEntry 를 재정의해 캐시로 사용할 수 있다.

Map에 새로운 키를 추가하는 put 메서드는 해당 메서드를 호출해 true가 반환되면 맵에서 가장 오래된 원소를 제거한다.

protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
   return size() > 100;
}

위와 같이 재정의한다면, 100개까지 재한하고 그 이후부터 원소를 제거하여 최근 원소 100개는 유지하도록 한다.

위에서 size()는 removeEldestEntryMap의 메서드라 호출이 가능하지만, 생성자에 넘기는 함수 객체는 이 맵의 인스턴스 메서드가 아니어서 자기 자신도 함수 객체에 내어줘야 한다.

@FuntionalInterface interface EldestEntryRemovalFunction<K, V> {
   boolean remove(Map<K, V> map, Map.Entry<K,V> eldest);
}

하지만 이 인터페이스는 자바 표준 라이브러리(java.util.function)에 존재하므로 직접 구현할 필요가 없다. 필요한 용도에 맞는 게 있다면, 직접 구현하지말고 표준 함수형 인터페이스를 활용해야한다.

✅ 기본 함수형 인터페이스

제목내용설명설명
UnaryOperatorT apply(T t)반환값과 인수의 타입이 같은 함수, 인수는 1개String::toLowerCase
BinaryOperatorT apply(T t1, T t2)반환값과 인수의 타입이 같은 함수, 인수는 2개BigInteger::add
Predicateboolean test(T t)한 개의 인수를 받아서 boolean을 반환하는 함수Collection::isEmpty
Function<T,R>R apply(T t)인수와 반환 타입이 다른 함수Arrays::asList
SupplierT get()인수를 받지 않고 값을 반환, 제공하는 함수Instant::now
Consumervoid accept(T t)한 개의 인수를 받고 반환값이 없는 함수System.out::println

표준 함수형 인터페이스 대부분은 기본 타입만 지원하지만 박싱된 기본 타입을 넣어 사용하지 않는 것이 좋다.

✅ @FuntionalInterface

이 애너테이션의 의미는 다음과 같다.

  1. 람다용으로 설계된 것을 알림
  2. 해당 인터페이스가 추상 메서드를 오직 하나만 가지고 있어야 한다.
  3. 유지보스 과정에서 실수로 추가하지 못하게 막아준다.

따라서 함수형 인터페이스는 항상 해당 애너테이션을 달 필요가 있다.

✅ 주의점

서로 다른 함수형 인터페이스를 같은 위치의 인수로 받는 메서드들을 다중 정의해서는 안된다. (아이템 52)

public interface ExecutorService extends Executor {
    // Callable<T>와 Runnable을 각각 인수로 하여 다중정의했다.
    // submit 메서드를 사용할 때마다 형변환이 필요해진다.
    <T> Future<T> submit(Callback<T> task);
    Future<?> submit(Runnable task);
}

위의 코드는 올바른 메서드를 알려주기 위해 형변환해야 할 때가 왕왕 생기게 된다.

reference

https://madplay.github.io/post/favor-the-use-of-standard-functional-interfaces

profile
💻 ☕️ 🏝 🍑 🍹 🏊‍♀️

0개의 댓글