본문 바로가기

java/이펙티브 자바

[item 21~22]

Item9~Item10 AJ
Item11~Item12 가을
Item13~Item14 AJ
Item15~Item16 김인호
Item17~Item18 민이/워니
Item19~Item20 Jake
Item21~Item22 워니/민이

 

 

item 21 인터페이스는 구현하는 쪽을 생각해 설계하라

 

자바 8 이전에는

기존 구현체를 깨뜨리지 않고

인터페이스에 메서드를 추가하는 방법이 없었다

 

인터페이스에 메서드를 추가하면 보통은 컴파일 오류가 나는데

추가된 메서드가 우연히 기존 구현체에 이미 존재할 가능성이 낮기 때문이다.

 

 

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

 

자바 8

Collection 인터페이스에 추가된 디폴트 메서드

 

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 인터페이스에 removeIf 메서드를 추가를 했다.

 

아파치의 SynchronizedCollection 클래스는

removeIf 디폴트 구현을 물려받게된다면

자신의 약속을 지키지 못하게 된다.

 

모든 메서드 호출을 알아서 동기화 해주지 못한다.

 

클래스들은  removeIf를 재정의하고

이를 호출하는 다른 메서드들은 디폴트 구현을 호출하기 전에 동기화함

 

디폴트 메서드는 컴파일에 성공하더라도

기존 구현테에 런타임 오류가 발생한다

 

 

기존 인터페이스에 디폴트 메서드로 새 메서드를 추가하는 것은 피해라.
차라리 새로운 인터페이스를 만들어라(아이템 20)

디폴트 메서드는 

인터페이스로부터 메서드를 제거하거나

기존 메서드의 시그니처를 수정하는 용도가 아니다

 

인터페이스를 변경하면 반드시 기존 클라이언트를 망가뜨리게 된다.

 

인터페이스를 설계할 때는 세심한 주의를 기울여라

 

 

새로운 인터페이스라면 릴리스 전에

반드시 테스트를 거쳐라

 

다른 방식으로 최소한 세 가지로 구현해봐라

 

다양한 작업에 활용하는 클라이언트도 여러 개를 만들어 봐라.

 

 

item 22 인터페이스 타입을 정의하는 용도로만 사용하라

 

 

 

 

인터페이스는 자신을 구현한 클래스의 인스턴스를 참조할 수 있는 타입 역할을 한다.

 

클래스가 어떤 인터페이스를 구현한다는 것은

자신의 인스턴스로 무엇을 할 수 있는 지를 클라인언트에게 말해주는 것이다

 

 

상수 인터페이스는 사용하지 마라

상수 인터페이스 안티 패턴은 인터페이스를 잘 못 사용한 예시이다.

 

//상수 인터페이스 안티패턴 - 사용하지 말 것! 
public interface PhysicalConstants { 
	//아보가드로 수(1/mol) 
	static final double AVOGADRO_NUMBER = 6.02214199e23; 

	//볼쯔만 상수(J/K) 
	static final double BOLZMANN_CONSTANT = 1.3806503e-23;
    
	//전자 질량(kg) 
	static final double ELECTRON_MASS = 9.10938188E-31;
}

 

클래스 내부에서 사용하는 상수는 

외부 인터페이스가 아닌

내부 구현에 해당한다.

 

여기에 final이 아니였으면

모든 하위 클래스의 이름공간이 

인터페이스가 정의한 상수들로 오염된다.

 

 

상수를 공개할 목적으로 하고 싶다?

방법1) 상수를 그 클래스나 인터페이스 자체에 추가한다

Inteager, Double에 선언된 MIN_VALUE, MAX_VALUE 상수가 예이다

 

방법 2) 열거 타입으로 공개하라

 

방법 3) 인스턴스화 할 수 없는 유틸리티 클래스에 담아 공개하자.

 

//상수 유틸리티 클래스 
package com.effective.java.science; 
public class PhysicalConstants { 
      private PhysicalConstants() { } //객체 생성을 막음
      
      public static final double AVOGADRO_NUMBER = 6.02214199e23; 
      public static final double BOLZMANN_CONSTANT = 1.3806503e-23; 
      public static final double ELECTRON_MASS = 9.10938188E-31;
}

 

클라이언트에서 유틸리티 클래스에서 정의된 상수를 사용할때는

클래스의 이름까지 명시해줘라

PhysicalConstants.AVOGADROS_NUMBER

 

틸리티 클래스에서 정의된 상수의 클래스 이름을 적기 싫다면

정적 임포트를 하여 클래스 이름은 생략할 수 있다.

import static com.github.sejoung.codetest.constantutilityclass.PhysicalConstants.AVOGADROS_NUMBER;
//정적 임포트
public class Test {
    double atoms(double mols){
        return AVOGADROS_NUMBER * mols;
    }
}

 

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

item 43~46  (0) 2022.01.16
Item29~30  (0) 2022.01.09
[item 1] 생성자 대신 정적 팩터리 메서드를 고려하라  (0) 2021.12.29
[item 17~18]  (0) 2021.12.29
[item 8] finalizer와 cleaner 사용을 피하라  (0) 2021.12.26