⭐ 자바 8에 와서 기존 인터페이스에 메서드를 추가할 수 있도록 디폴트 메서드를 소개했지만 그 위험이 완전히 사라진 것은 아니다.
자바 8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가되었다. 주로 람다를 활용하기 위해서다.
하지만, 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어려운 법이다.
자바 8의 Collection 인터페이스에 추가된 디폴트 메서드
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 구현체와 잘 어우러지는 것은 아니다.
대표적인 예가 아파치의SynchronizedCollection
이다. 아파치 버전은 클라이언트가 제공한 객체로 락을 거는 능력을 추가로 제공한다.
즉, 모든 메서드에서 주어진 락 객체로 동기화한 후 내부 컬렉션 객체에 기능을 위임하는 래퍼 클래스이다.
하지만,removeIf
의 구현은 동기화에 관한 아무것도 모르므로 락 객체를 사용할 수 없다. 따라서SynchronizedCollection
인스턴스를
여러 스레드가 공유하는 환경에서 한 스레드가removeIf
를 호출하면ConcurrentModificationException
이 발생하거나 다른 예기치
못한 결과로 이어질 수 있다.디폴트 메서드는 (컴파일에 성공하더라도) 기존 구현체에 런타임 오류를 일으킬 수 있다.
인터페이스를 설계할 때는 여전히 세심한 주의를 기울여야 한다.
인터페이스를 릴리스한 후라도 결함을 수정하는 게 가능한 경우도 있겠지만, 절대 그 가능성에 기대서는 안된다.
참고 자료
Joshua Bloch, 『Effective Java 3/E』, 개앞맵시 옮김, 프로그래밍인사이트(2018)
http://www.kyobobook.co.kr/product/detailViewKor.laf?ejkGb=KOR&mallGb=KOR&barcode=9788966262281&orderClick=LEa&Kc=
'Java' 카테고리의 다른 글
[Effective Java] 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라. (0) | 2023.03.20 |
---|---|
[Effective Java] 아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라. (0) | 2023.03.20 |
[Effective Java] 아이템 20. 추상 클래스보다는 인터페이스를 우선하라. (0) | 2022.05.24 |
[Effective Java] 아이템 18. 상속보다는 컴포지션을 사용하라. (0) | 2022.05.24 |
[Effective Java] 아이템 17. 변경 가능성을 최소화하라. (0) | 2022.05.24 |