1. 디폴트 메서드
Java 8 부터는 기존의 구현체를 깨뜨리지 않고 인터페이스에 디폴트 메서드를 추가할 수 있다. 그러나 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기 어렵다.
1.1. SynchronizedCollection 예시
아파치의 SynchronizedCollection은 메서드를 락 객체로 동기화한 후 내부 컬랙션 객체에게 기능을 위임하는 래퍼 클래스이다. removeIf()를 재정의하고 있지 않다.
- 만약 Java 8의 동기화 되지 않은 removeIf() 디폴트 구현을 물려받는다면?
- removeIf()의 구현은 동기화를 모르기 때문에 락 객체를 사용할 수 없다.
- 멀티 쓰레드 상황에서 호출하면 에러가 발생할 수 있다.
Java 플랫폼 라이브러리들은 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 한다.
- Collections.synchronizedCollection이 반환하는 package-private 클래스들은 removeIf를 재정의한다.
- 이를 호출하는 메서드들은 디폴트 메서드 사용 전에 동기화하도록 한다.
- 그러나 Java 플랫폼 라이브러리가 아닌 제 3의 기존 컬렉션 구현체들은 이런 변화에 발맞춰 수정되지 않아 문제가 되었다.
1.2. 주의사항
기존 인터페이스에 디폴트 메서드를 추가하는 것은 꼭 필요한 경우가 아니면 피해야 한다. 디폴트 메서드들은 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 낼 수 있다. 처음 인터페이스를 설계할 때부터 주의를 기울여야 한다.
'Prodo 독서 리뷰' 카테고리의 다른 글
[Effective Java] Item 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 (0) | 2021.04.12 |
---|---|
[Effective Java] Item 22. 인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2021.04.12 |
[Effective Java] Item 20. 추상 클래스보다는 인터페이스를 우선하라 (0) | 2021.04.12 |
[Effective Java] Item 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2021.04.12 |
[Effective Java] Item 18. 상속보다는 컴포지션을 사용하라 (0) | 2021.04.11 |