Skip to content

Latest commit

 

History

History
52 lines (38 loc) · 2.81 KB

item21.md

File metadata and controls

52 lines (38 loc) · 2.81 KB

인터페이스는 구현하는 쪽을 생각해 설계하라


  • 자바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줄 요약

  • 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 꼭 필요한 경우가 아니면 피해야 하며,

    추가하려는 디폴트 메서드가 기존 구현체들과 충돌하지 않을지 고려해야 함

  • 디폴트 메서드는 인터페이스로부터 메서드를 제거하거나 기존 메서드의 시그니처를 수정하는 용도가 아님

    그러니 디폴트 메서드라는 게 생겼어도, 인터페이스 설계시 여전히 주의를 기울여야 함

  • 새 인터페이스라면 릴리즈 전 반드시 테스트를 거쳐야 하며,

    각 인터페이스의 인스턴스를 다양한 작업에 활용하는 클라이언트도 여러 개 만들어 봄으로써

    의도한 용도랑 잘 맞는지 확인해야 함