# Item 17. 변경 가능성을 최소화하라

## 불변 클래스

### 불변 클래스의 안정성

* 객체가 파괴(회수)될 순간까지 객체 내부의 값이 절대 달라지지 않음
* 가변 클래스에 비해 설계와 구현이 쉬우며, `오류가 덜 생김`
* 불변 객체는 `스레드 안정성(Thread-Safe)`를 보장
  * 스레드 안정성은 여러 스레드가 하나의 리소스를 동시에 사용하며 상태를 변경시키게 되면 깨지는데, 불변 객체는 애초에 상태가 변경될 일이 없어 여러 스레드에서 동시에 사용해도 문제가 없음
  * 따라서, 불변 객체는 멀티 스레드 환경에서 안심하고 사용할 수 있음
* 불변 객체는 `실패 원자성`을 제공
  * 상태가 변하지 않기 때문에, 일부 로직의 실패에 의해 객체가 불일치 상태에 빠질 염려가 없음

### 불변 클래스를 구현하는 방법

* 객체의 상태를 변경하는 메서드(`변경자`)를 제공하지 않아야 함
* 하위 클래스에서 객체를 변경하는 것을 막기 위해, 확장 불가능 클래스로 선언
  * 이를 달성하기 위한 두 가지 방법이 있음
    1. final 클래스로 선언
    2. private 생성자를 명시하고 정적 팩토리 메서드를 제공
* 모든 필드를 private으로 선언해 외부에서 이를 수정하는 것을 방지
  * 불변과는 연관이 없으나, public으로 선언하면 외부에 노출되므로 추후 내부 표현을 바꿀 수 없음
* 모든 필드를 final로 선언해 생성자 호출 시점 이후의 값 변경을 막음
* 클래스 내부를 제외하고, 클래스 내부의 필드가 참조하는 가변 객체로의 접근을 막음

## 불변 클래스를 사용할 때 주의할 점

* 불변 클래스는 객체의 상태가 불변임을 보장해 안정성 면에서는 좋은 선택이지만, `약간의 수정이 필요한 경우에도 새 객체를 만들어야 하기 때문에` 성능 문제를 일으킬 수 있음
* 이를 예방하기 위해서는 최대한 객체를 `재사용`해야 함
* 이를 위해 정적 팩토리 메서드(Item 1)과 연관지어, 생성자를 통해 인스턴스를 획득하는 대신 정적 팩토리를 이용하고 이 메서드 내부에서 `캐싱`을 이용하는 것도 좋음
* 새 객체를 얻기 위해 여러 번의 상태 변환을 거쳐야 해서 여러 번의 중간 단계 객체가 생길 수 있는 경우에는 이들을 하나의 단계로 묶어서 처리하는 것이 좋음
* 불변 객체는 값이 변경되지 않기 때문에 불변 객체 간에 같은 내부 데이터를 공유해도 문제가 없음
* 불변 클래스는 복사 메서드를 제공할 필요가 없음
  * 복사하는 대신 자기 자신을 이용하면 되기 때문

## 핵심 정리

* 불변 클래스는 안정성 면에서 뛰어남
* 불변 클래스는 성능 이슈를 야기할 수 있으나 정적 팩토리 메서드를 제공하거나 캐싱을 도입하는 등의 방법으로 일부 예방이 가능
* 불변으로 만드는 것이 가장 좋고, 그럴 수 없어 가변으로 만들어야 한다고 해도 최대한 `변경 가능한 부분을 최소화`하는 것이 안정성 면에서 좋음
  * 합당한 이유가 없다면 필드는 private final으로 선언해 외부에서 접근 및 조작이 불가능하도록 하는 것이 좋음
