간펴니
간편 자바프로그래밍
간펴니
전체 방문자
오늘
어제
  • 전체보기 (185)
    • 알고리즘 (2)
    • JAVA (69)
      • 이펙티브 자바 (47)
      • JAVA 병렬프로그래밍 (5)
      • 자바 (17)
    • SPRING (60)
      • Spring (12)
      • IceWater Community (37)
      • Homme Shop (10)
      • 토비의 스프링 (1)
    • SPRING BOOT (4)
      • WhiteRecord (7)
    • 오류 (9)
    • DB (10)
      • ORACLE (5)
      • MYSQL (1)
      • MYBATIS (4)
      • JPA (0)
      • 대용량 데이터 베이스 (0)
      • SQL (0)
    • FRONT (8)
      • JSP (2)
      • JavaScript (2)
      • Jquery (3)
      • Thymeleaf (1)
    • AWS (6)
    • JNI (10)
    • 회고 (0)
    • MQ (0)
    • Radis (0)
    • Git (0)
    • Docker (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 블로그 컨셉 변경

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
간펴니

간편 자바프로그래밍

JAVA/이펙티브 자바

21. 인터페이스는 구현하는 쪽을 고려해 설계해라( default 메서드)

2023. 7. 6. 20:56
728x90

자바 8 전에는 기존 구현체를 깨뜨리지 않고 인터페이스에 메서드를 추가할 방법은 존재하지 않았다.

자바 8부터 디폴트 메서드를 통해서 기존 인터페이스에 메서드를 추가할 수 있게 되었다.

 

디폴트 메서드를 선언하면, 그 인터페이스를 구현한 후 디폴트 메서드를 재정의하지 않은 모든 클래스에서 디폴트 구현이 쓰이게 된다.

 

단, 이렇게 디폴트 메서드를 추가한다고 해도 기존 구현체들과 매끄럽게 연동된다는 보장은 없다.

 

생각 할 수 있는 모든 상황에서 불변식을 해치지 않는 디폴트 메서드를 작성하기란 어렵기 때문이다.

 

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;
}

 

Collection의 removelef 디폴트 메서드 이다.

 

이 코드는 범용적으로 작성되었지만 현존하는 모든 Collection 구현체와 잘 어우러지지는 못한다.

 

대표적인 예가 SyncronizedCollection 이다.

 

이 클래스는 클라이언트가 제공한 객체로 락을 거는 능력을 추가로 제공한다.

 

모든 메서드에서 주어진 락 객체로 동기화한 후 내부 컬렉션 객체에 기능을 위임하는 래퍼 클래스다.

 

현재는 해당 클래스가 removeIf 메서드를 재정의하지 않기 때문에 removeIf 메서드는 동기화에 관해 알지 못하므로 락 객체를 사용할 수가 없다.

 

SynchronizedCollection 인스턴스를 여러 스레드가 공유하는 환경에서 한 스레드가 removeIf를 호출하면 에러가 발생할 가능성이 있다.

 

    @Override
    public boolean removeIf(final Predicate<? super E> filter) {
        synchronized (lock) {
            return decorated().removeIf(filter);
        }
    }

 

이렇게 메서드를 재정의해서 해결 할 수 있다.

 

디폴트 메서드는 컴파일에 성공하더라도 기존 구현체에 런타임 오류를 일으킬수 있다.

 

때문에 기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 일은 피해야한다.

 

반면, 새로운 인터페이스를 만드는 경우라면 표준적인 메서드 구현을 제공하는데 아주 유용한 수단이며, 그 인터페이스를 

 

더 쉽게 구현해 활용할 수 있게끔 해준다.

 

디폴트 메서드라는 도구가 생겼지만 인터페이스를 설계할 때는 여전히 주의를 기울일 필요가 있다.

 

기존 인터페이스에 디폴트 메서드를 추가할 시 어떤 위험이 딸려올지 알 수 없기 때문이다.

 

 

728x90
저작자표시 (새창열림)

'JAVA > 이펙티브 자바' 카테고리의 다른 글

23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 ( 클래스 계층구조 )  (0) 2023.07.06
22. 인터페이스는 타입을 정의하는 용도로만 사용하라 ( 상수 공개 )  (0) 2023.07.06
20. 추상 클래스보다는 인터페이스를 우선하라(템플릿 메서드 패턴)  (0) 2023.07.03
19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라  (0) 2023.07.03
18. 상속보다는 컴포지션을 사용하라  (1) 2023.07.01
    'JAVA/이펙티브 자바' 카테고리의 다른 글
    • 23. 태그 달린 클래스보다는 클래스 계층구조를 활용하라 ( 클래스 계층구조 )
    • 22. 인터페이스는 타입을 정의하는 용도로만 사용하라 ( 상수 공개 )
    • 20. 추상 클래스보다는 인터페이스를 우선하라(템플릿 메서드 패턴)
    • 19. 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라
    간펴니
    간펴니
    개발공부 기록하는 곳

    티스토리툴바