아이템21. 인터페이스는 구현하는 쪽을 생각해 설계하라
2022-01-27 00:00:00 # Effective_Java
  • 디폴트 메서드에 대한 이야기…
  • 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다.

Collection 인터페이스에 있는 removeIf 메서드 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.Iterator;
import java.util.Objects;
import java.util.function.Predicate;

interface Sample {
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean result = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (filter.test(it.next())) {
it.remove();
result = true;
}
}
return result;
}
}
  • predicate 함수가 true를 반환하는 모든 원소를 제거하는 메서드
  • SynchronizedCollection 클래스는 클라이언트가 제공한 객체로 락을 거는 능력이 제공되는데
    removeIf를 자바8과 사용한다면 모든 메서드 호출을 알아서 동기화해주지 못하게 된다.
  • removeIf의 구현은 동기화에 관해 아무것도 모르기에 락 객체를 사용할 수 없다.
  • 따라서 SynchronizedCollection 인스턴스를 여러 스레드가 공유하는 환경에서 한 스레드가 removeIf를 호출하면 예외발생할 것임.

예방책?

  • 자바 플랫폼 라이브러리에서 이런 문제를 예방하기 위한 조치
  • 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 했다.
  • 하지만 자바 플랫폼에 속하지 않은 제3의 기존 컬렉션 구현체들은 이런 변화에 맞춰 수정될 기회가 없어서 수정이 안 된 것도 있다 한다.

디폴트 메서드

  • 디폴트 메서드는 컴파일에 성공해도 기존 구현체에 런타임 오류를 일으킬 수 있다.
  • 꼭 필요한 경우가 아니면 피하자
  • 디폴트 메서드라는 도구가 생겼더라도 인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다.
  • 새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야 한다.
  • 인터페이스를 배포한 후라도 결함을 수정하는게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안 된다.