스터디/이펙티브 자바

[Effective Java] Item17. 변경 가능성을 최소화

📝 작성 : 2022.05.29  ⏱ 수정 : 
728x90

불변 클래스의 정의

인스턴스의 내부 값을 수정할 수 없는 클래스로 객체가 파괴되는 순간까지 절대 달라지지 않습니다. 대표적으로 String 클래스가 해당합니다.

불변 클래스의 장점

  1. 가변 클래스보다 설계, 구현, 사용이 쉽습니다.
  2. 가변 클래스보다 오류 발생 가능성이 적고 안전합니다.
  3. 기본적으로 Tread-safe하므로 안심하고 공유할 수 있어서 재사용을 할 수 있습니다.
  4. 방어적 복사를 할 필요가 없습니다. 따라서 clone메서드나 복사 생성자를 제공하지 않는 것이 좋습니다.
  5. 불변 객체는 그 자체로 실패 원자성(메서드에서 예외가 발생해도 그 객체는 메서드 호출전과 똑같은 유요한 상태여야 함)을 제공합니다.

불변 객체끼리는 내부 데이터를 공유할 수 있습니다.

public class BigInteger {
    final int signum; //부호
    final int[] mag; //크기(절대값)

    public BigInteger negate() {
        //배열(mag)은 가변이지만 복사하지 않고 원본과 공유해도 됩니다.
        //원본 인스턴스가 가리키는 내부배열을 그대로 가리킵니다.
        return new BigInteger(this.mag, -this.signum);
    }
}

불변 클래스의 단점

  • 값이 다르면 반드시 독립된 객체로 만들어야 합니다.

불변 클래스 재사용 방법

  • 자주 쓰이는 값들을 상수로 제공(public static final)
  • 자주 사용되는 인스턴스를 캐싱하여 중복생성을 방지핳는 정적 팩토리를 제공합니다. 이러면 메모리 사용량과 GC비용이 줄어듭니다. 또한, 필요에 따라 클라이언트를 수정하지 않고도 캐시 기능을 덧붙일 수 있습니다.

불변 클래스를 만드는 규칙

  1. 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않습니다.
  2. 클래스를 확장할 수 없도록 합니다. 대표적으로 클래스를 final로 선언하거나 private(또는 default)생성자와 public 정적 팩토리 메서드를 제공
  3. 모든 필드를 final로 선언합니다. 이는 인스턴스를 동기화 없이 다른 스레드로 건네도 문제없이 동작하게끔 보장하는데도 필요합니다.
  4. 모든 필드를 private로 선언합니다. public final로 선언해도 되지만 나중에 내부 표현을 바꾸지 못하므로 private을 권장합니다.
  5. 자신 외에는 가변 컴포넌트에 접근할 수 없도록 합니다. 생성자, 접근자 모두 방어적 복사를 합니다.

정리

모든 클래스를 불변 클래스로 만들 수는 없습니다. 그래도 변경 가능한 부분은 최소한으로 줄이는 것이 좋습니다. 그러니 꼭 변경해야하는 필드를 제외하고 모두 private final인 것이 좋습니다.
생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 합니다.
생성자와 정적 팩토리 메서드를 제외한 그 어떤 초기화 메서드도 public으로 제공해서는 안됩니다.

반응형