반응형
이 포스팅에서 작성하는 내용은 EFFECTIVE JAVA(이펙티브자바) 에서 발췌하였습니다.
아이템 21. 인터페이스는 구현하는 쪽을 생각해 설계하라
인터페이스의 디폴트 메서드
- 자바 8 이전에는 기존 구현체를 깨뜨리지 않고는 인터페이스에 메서드를 추가할 수 없었다.
인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데, 추가된 메서드가 우연히 기존 구현체에 이미 존재할 가능성은 아주 낮기 때문. - 자바 8에서부터는 기존 인터페이스에 메서드를 추가할 수 있지만, 위험이 완전히 사라진 것은 아니다.
- 디폴트 메서드를 선언하면 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지않은 모든 클래스에서 디폴트 구현이 쓰이게 됨
(모든 기존 구현체들과 매끄럽게 연동되리라는 보장은 없음) - 디폴트 메서드는 구현 클래스에 대해 아무것도 모른 채 합의 없이 무작정 '삽입' 될 뿐이다.
- 자바 8에서는 핵심 컬렉션 인터페이스들에 다수의 디폴트 메서드가 추가되었음(람다를 활용하기 위해)
- 자바 라이브러리의 디폴트 메서드는 코드 품질이 높고 범용적이라 대부분 상황에서 잘 작동함
- 생각할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하는 것은 어렵다.
ex) 자바 8의 Collection 인터페이스에 추가된 removeIf 메서드
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean result = false;
for (Iterator<E> it = iterator(); it.hasNext(); ) {
if (filter.test(it.next())) {
it.remove();
result = true;
}
}
return result;
}
- 이 메서드는 주어진 Boolean 함수(predicate)가 true를 반환하는 모든 원소를 제거한다.
- 디폴트 구현은 반복자를 이용해 순회하면서 각 원소를 인수로 넣어 predicate 를 호출하고, predicate가 true를 반환하면 반복자의 remove 메서드를 호출해 그 원소를 제거하는 방식
- 이 코드보다 더 범용적으로 구현하기도 어렵겠지만, 현존하는 모든 Collection 구현체와 잘 어우러지는 것은 아님.
- ex) apache.commons.collections4.collection.SynchronizedCollection
- 아파치 버전은 클라이언트가 제공한 객체로 락을 거는 능력을 추가로 제공함
- 모든 메서드에서 주어진 락 객체로 동기화 한 후 내부 컬렉션 객체에 기능을 위임하는 래퍼클래스다.
- 아파치의 SynchronizedCollection 클래스는 여전히 관리되고있지만, 이 책이 나온 시점엔 removeIf 메서드를 재정의하지 않음
- 즉, SynchronizedCollection 인스턴스를 여러 스레드가 공유하는 환경에서 한 스레드가 removeIf를 호출하면 예외가 발생하거나 의도대로 동작하지 않을 수 있음
- 자바 플랫폼 라이브러리에서도 이런 문제를 예방하기 위해 일련의 조치를 함
ex) 구현한 인터페이스의 디폴트 메서드를 재정의하고, 다른 메서드에서는 디폴트 메서드를 호출하기 전에 필요한 작업을 수행하도록 함
인터페이스의 디폴트 메서드 주의점
- 디폴트 메서드는 (컴파일에 성공하더라도) 기존 구현체에 런타임 오류를 일으킬 수 있다.
- 디폴트 메서드로 기존 인터페이스에 새로운 메서드를 추가하면 커다란 위험도 딸려 온다.
- 새로운 인터페이스라면 릴리스 전에 반드시 테스트를 거쳐야 함
- 인터페이스를 릴리스한 후에 결함을 수정할 수는 있지만 좋지 않다.
반응형
'BE > Java' 카테고리의 다른 글
[Effective Java] 아이템 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 (1) | 2022.09.30 |
---|---|
[Effective Java] 아이템 22. 인터페이스는 타입을 정의하는 용도로만 사용하라 (0) | 2022.09.29 |
[Effective Java] 아이템 20. 추상 클래스보다는 인터페이스를 우선하라 (0) | 2022.09.27 |
[Effective Java] 아이템 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (1) | 2022.09.26 |
[Effective Java] 아이템 18. 상속보다는 컴포지션을 사용하라 (1) | 2022.09.22 |