-
자바8 이전 - 기존 구현체를 깨뜨리지 않고 인터페이스에 메서드 추가 불가능
- 인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 났음
-
자바8 이후 - 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가됨
- but 모든 기존 구현체들과 매끄럽게 연동 보장 X
- 주로 람다를 활용하기 위해 디폴트 메서드가 추가됨
추가된 예시) Collection 인터페이스에 추가된 removeIf 메서드
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를 반환하는 모든 원소를 제거함
- 디폴트 구현은 반복문으로 순회하며 원소를 인수로 넣어 프레디키트를 호출하고, 프레디키트가 true를 반환하면 반복자의 remove 메서드를 호출해 그 원소를 제거함
-
아파치의 SynchronizedCollection 클래스는 (책 기준 시점: 4.4버전) removeIf 메서드를 재정의하지 않음 (4.4버전부터 동기적으로 override되도록 수정됨)
- 재정의 되지 않은 상황에서, 모든 메서드 호출을 알아서 동기화해주지 못하기 때문에 락 객체 사용 못함
- 따라서 SynchronizedCollection 인스턴스를 여러 스레드가 공유하는 환경에서, 한 스레드가 removeIf를 호출시 ConcurrentModificationException 발생 혹은 예기치 못한 결과로 이어짐
-
자바는 이런 문제 예방을 위해,
- 구현한 인터페이스의 디폴트 메서드를 재정의하고
- 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 함
긴 3줄 요약
-
기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 하며,
추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 고려해야 함
-
디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님
그러니 디폴트 메서드라는 게 생겼어도, 인터페이스 설계시 여전히 주의를 기울여야 함
-
새 인터페이스라면 릴리즈 전 반드시 테스트를 거쳐야 하며,
각 인터페이스의 인스턴스를 다양한 작업에 활용하는 클라이언트도 여러 개 만들어 봄으로써
의도한 용도랑 잘 맞는지 확인해야 함