Book Review/effective-java

[ITEM17]변경 가능성을 최소화하라

jay Joon 2021. 2. 14. 02:06

ITEM 17

변경 가능성을 최소화하라

서론

불변 클래스는 가변 클래스보다 설계, 구현하기가 쉽다. 또한 오류가 생길 여지도 적고 훨씬 안전하다.

클래스를 불변으로 만드는 5가지 규칙

  1. 객체 상태를 변경하는 메서드(변경자)를 제공하지 않는다.( ex: setter 메서드 )

  2. 클래스를 확장할 수 없도록 한다.

  3. 모든 필드를 final로 선언한다.

  4. 모든 필드를 private 으로 선언한다.

  5. 자신 외에는 내부 가변 컴포넌트에 접근할 수 없도록 한다.

    -> 만약 접근자 메서드를 통해 내부 가변 값을 반환해야 한다면 방어적 복사를 수행하자.

불변 객체의 장점

  1. 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요 없다.

    -> 객체의 변동이 없으니 여러 스레드에서 접근해도 절대 훼손되지 않는다.

  1. 한번 만든 인스턴스는 최대한 재활용 하자.

    -> 정적 팩터리 (아이템 1)를 제공할 수 있다. (Ex: Biginteger.class)

  1. 방어적 복사가 필요 없다

    -> 불변 객체를 복사해도 항상 원본이랑 같기 때문에 굳이 clone 메서드나 복사 생성자를 제공하지 말자.(불필요한 객체 생성 방지)

  1. 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변 객체끼리는 내부 데이터를 공유할 수 있다.
  1. 객체를 만들 때 다른 불변 객체들을 구성요소로 사용하면 이점이 많다.

    -> 유일 값이기 때문에 예를 들어 (Set)의 원소로 쓰기 안성맞춤이다. 즉 불변식을 유지할 수 있다.

  1. 불변 객체는 그 자체로 실패 원자성을 제공한다.(아이템 76)

    -> 상태가 절대 변하지 않으니 잠깐이라도 불일치 상태에 빠질 가능성이 없다.

불변 객체의 단점

  1. 값이 다르면 반드시 독립된 객체로 만들어야 한다.

    -> 값의 가짓수가 많다면 이들을 많이 만드는데 많은 비용이 든다.

예를 들면

   public static void main(String[] args) {
       String count = "";
       for (int i = 0; i <10; i++) {
           count +=String.valueOf(i);
           System.out.println(count);
       }
   }

다음과 같은 경우 String의 인스턴스를 계속해서 만든다.

따라서 다음과 같은 경우 StringBuilder 가변 동반 클래스를 제공하자.

불변 클래스를 만드는 설계 방법

  1. final 클래스로 선언 -> 상속을 못하게 한다.

    해당 방법보다 모든 생성자를 private 혹은 package-private으로 만들고 정적 팩토리(아이템 1)를 제공하자

    이 방법이 조금 더 유연한 방법이다.

결론

  1. getter 메서드가 있다고 해서 무조건 setter를 만들지는 말자.

    -> 클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다.

  1. 불변으로 만들 수 없는 클래스라도 변경할 수 있는 부분을 최소한으로 줄이자.

    -> 꼭 변경해야 할 필드를 뺀 나머지는 final로 선언하자.

    -> 아이템 15의 조언과 종합하자면 다른 합당한 이유가 없다면 모든 필드는 private final 이어야 한다.

  1. 생성자는 불변식 설정이 모두 완료된 , 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다.

    ->확실한 이유가 없다면 생성자와 정적 팩토리 외에는 그 어떤 초기화 메서드도 public dmfh wp