본문 바로가기

공부 기록/Java

[이펙티브 자바 3/E] 아이템17 - 변경 가능성을 최소화하라

- 불변 클래스 : 인스턴스의 내부 값을 수정할 수 없는 클래스

 

불변 클래스를 만드는 규칙

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

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

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

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

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


- 함수형 프로그래밍 : 피연산자에 함수를 적용해 그 결과를 반환하지만, 피연산자 자체는 그대로인 프로그래밍 패턴 => 코드에서 불변이 되는 영역의 비율이 높아지는 장점을 누릴 수 있다.

 

- 불변 객체는 근본적으로 스레드 안전하여 따로 동기화할 필요가 없다. => 안심하고 공유할 수 있다. => 방어적 복사(아이템 50)도 필요 없다.(clone 메서드나 복사 생성자(아이템 13)를 제공하지 않는 게 좋다.)

- 불변 클래스는 자주 사용되는 인스턴스를 캐싱하여 같은 인스턴스를 중복 생성하지 않게 해주는 정적 팩터리(아이템 1)를 제공할 수 있다. => 여러 클라이언트가 인스턴스를 공유하여 메모리 사용량과 가비지 컬렉션 비용이 줄어든다.

- 불변 객체는 자유롭게 공유할 수 있음은 물론, 불변 객체끼리는 내부 데이터를 공유할 수 있다.

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

* 실패 원자성 : 메서드에서 예외가 발생한 후에도 그 객체는 여전히 (메서드 호출 전과 똑같은) 유효한 상태여야 한다는 성질

- 불변 클래스의 단점 : 값이 다르면 반드시 독립된 객체로 만들어야 한다.


- 클래스를 상속하지 못하게 하는 더 유연한 방법은 모든 생성자를 private 혹은 package-private으로 만들고 public 정적 팩터리를 제공하는 방법이다(아이템 1).

public class Complex {
    private final double re;
    private final double im;
    
    private Complex(double re, double im) {
        this.re = re;
        this.im = im;
    }
    
    public static Complex valueOf(double re, double im) {
        return new Complex(re, im);
    }
    
    ...
    
}

[핵심 정리]

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

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

- 다른 합당한 이유가 없다면 모든 필드는 private final이어야 한다.

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