public interface Car {
default void move() {
System.out.println("움직인다!");
}
}
- 기존에는 인터페이스에 새로운 메서드를 추가할 수 없었다.
- 자바 8에 도입된 default 메서드로 기존 구현체 변경 없이 메서드를 추가할 수 있게 되었다.
- 그러나, 기존 구현체에서도 제대로 작동하리라는 보장이 전혀 없다!
[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 구현체와 어우러지는 것은 아니다.
[주어진 객체에 락을 걸고 내부 컬렉션에 기능을 위임하는 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개는 구현해보자, 이를 활용하는 클라이언트도 만들어보자)