Skip to content

Latest commit

 

History

History
58 lines (48 loc) · 2.3 KB

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

File metadata and controls

58 lines (48 loc) · 2.3 KB

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

자바 8부터 추가된 인터페이스 디폴트 메서드

public interface Car {

    default void move() {
        System.out.println("움직인다!");
    }
}
  • 기존에는 인터페이스에 새로운 메서드를 추가할 수 없었다.
  • 자바 8에 도입된 default 메서드로 기존 구현체 변경 없이 메서드를 추가할 수 있게 되었다.
  • 그러나, 기존 구현체에서도 제대로 작동하리라는 보장이 전혀 없다!

자바 8 Collection 인터페이스에 추가된 디폴트 메서드

[Predicate가 true인 원소만 제거하는 메서드]

    default boolean removeIf(Predicate<? super E> filter) {
        Objects.requireNonNull(filter);
        boolean removed = false;
        final Iterator<E> each = iterator();
        while (each.hasNext()) {
            if (filter.test(each.next())) {
                each.remove();
                removed = true;
            }
        }
        return removed;
    }
  • 범용적으로 잘 구현된 코드지만, 모든 Collection 구현체와 어우러지는 것은 아니다.

Apache commons의 SynchronizedCollection

[주어진 객체에 락을 걸고 내부 컬렉션에 기능을 위임하는 wrapper 클래스]

    private final Collection<E> collection;
    protected final Object lock;

    @Override
        public boolean remove(final Object object) {
            synchronized (lock) {
                return decorated().remove(object);
            }
        }
  • 해당 클래스에는 removeIf가 재정의되지 않았고, 그러므로 인터페이스의 디폴트 메서드를 사용하게 되면 동기화를 할 수 없다.
  • 스레드가 공유되는 환경에서 removeIf를 호출하면 ConcurrentModificationException이 발생하거나 예기치 못한 결과로 이어질 수 있다.

결론

  • 디폴트 메서드라는 기능이 생겼다하더라도 인터페이스 설계에는 세심한 주의가 필요하다. (디폴트 메서드는 커다란 위험성을 내재하고 있다!)
  • 새로운 인터페이스를 설계한다면, 의도한 용도에 잘 부합하는 지 확인해 릴리즈 전에 수정하자. (최소 구현체 3개는 구현해보자, 이를 활용하는 클라이언트도 만들어보자)