티스토리 뷰
핵심 정리
- 기존 인터페이스에 디폴트 메서드 구현을 추가하는 것은 위험한 일이다.
- 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 “삽입”될 뿐이다.
- ex) 자바 8 Collection 인터페이스의 removeIf() 메서드를 재정의하지 않은 아파치의 SynchronizedCollection
- SynchronizedCollection 인스턴스에서 removeIf()를 호출할 경우 ConcurrentModificationException이 발생하거나 다른 예기치 못한 결과로 이어질 수 있다
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;
}
- 디폴트 메서드는 기존 구현체에 런타임 오류를 일으킬 수 있다.
public interface MarkerInterface {
default void hello() {
System.out.println("hello interface");
}
}
public class SuperClass {
private void hello() {
System.out.println("hello class");
}
}
public class SubClass extends SuperClass implements MarkerInterface {
public static void main(String[] args) {
SubClass subClass = new SubClass();
subClass.hello();
}
}
- 인터페이스를 설계할 때는 세심한 주의를 기울여야 한다.
- 서로 다른 방식으로 최소한 세 가지는 구현을 해보자.
ConcurrentModificationException
- 현재 바뀌면 안되는 것을 수정할 때 발생하는 예외
- 멀티 스레드가 아니라 싱글 스레드 상황에서도 발생할 수 있다
- ex) fail-fast 이터레이터를 사용해 콜렉션을 순회하는 중에 콜렉션을 변경하는 경우
public class FailFast {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
numbers.add(1);
numbers.add(2);
numbers.add(3);
numbers.add(4);
numbers.add(5);
// 이터레이터로 컬렉션을 순회하는 중에 Collection의 remove를 사용한다면...
for (Integer number : numbers) {
if (number == 3) {
numbers.remove(number);
}
}
}
}

