[아이템 17] 변경 가능성을 최소화하라
불변 클래스는 서버가 내려갈 때까지(객체가 파괴되는 순간) 인스턴스 내부의 값이 절대로 바뀌지 않는 클래스다. 자바도 String, primitive types(int, char, double, float 등) 의 박싱된 클래스, BigInteger, BigDecimal 등이 자바에서 제공하는 불변 클래스다. 불변 클래스는 설계 및 구현이 쉽고 오류가 생길 가능성이 적다. *가변 클래스는 프로그램을 작성하면서 값이 변경되고 잘 못 변경된 값으로 인해 시스템 오류가 생길 수 있으나 불변 클래스는 소멸될 때까지 값이 변하지 않아 값 변경으로 인한 오류가 발생할 여지가 없다.
불변 클래스 생성 규칙
- 객체의 상태를 변경하는 setter 메서드를 제공하지 않는다.
- 클래스를 확장할 수 없도록 한다.
- 모든 필드를 final로 선언한다. (https://docs.oracle.com/javase/specs/jls/se17/html/jls-17.html#jls-17.5) 이는 개발자로 하여금 동기화없이 thread-safe한 불변의 객체를 구현할 수 있게해준다.
- 모든 필드를 private으로 선언한다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다. 생성자, 접근자, readObject 메서드(아이템 88) 모두에서 방어적 복사를 수행해야한다.
인스턴스 자신은 수정하지 않고 새로운 인스턴스를 만들어 반환하는 프로그래밍 패턴을 함수형 프로그래밍이라 한다. 이와 달리 절차적 혹은 명령형 프로그래밍에서는 메서드에서 피연사자인 자신을 수정해 자신의 상태가 변하게 된다. 불변 객체는 thread safe하여 따로 동기화할 필요가 없다. 이러한 특성을 활용하여 불변 객체는 최대한 reuse를 하면 메모리 사용량과 가비지 컬렉션 비용이 줄어든다.(성능이 좋아진다.) 불변 클래스는 자주 사용되는 인스턴스를 정적 팩터리를 사용하여 캐싱할 수 있다.
* 불변 객체의 단점 : 값이 다르면 반드시 독립된 객체로 만들어야한다. 불변 객체의 값의 가짓수가 많으면 이들을 만드는데 많은 비용이 든다. 그래서 BigInteger에서는 내부적으로 가변 동반 클래스를 사용하여 연산 속도를 높여준다. String 클래스는 새로운 문자열이 생성될 때마다 상수화된 문자열 객체를 만들기에 잦은 변경이 일어날 경우 가변 동반 클래스인 StringBuilder를 사용하면 된다.
가변 클래스도 객체가 가질 수 있는 상태의 수를 줄여 예측하기 쉽고 오류가 생길 여지를 차단하는게 좋다. 이를 위해 꼭 변경해야 할 필드를 뺀 나머지 모두를 final로 선언하자. 객체를 재활용할 목적으로 필드를 초기화하는 메서드를 제공하면 성능 이점 대신 복잡성만 커지고 오류가 발생할 확률이 커진다.
클래스는 꼭 필요한 경우가 아니라면 불변이어야 한다.
뒷 장에서 확인할 내용
불변 객체를 자유롭게 공유할 수 있다는 점은 방어적 복사(아이템 50)도 필요 없다는 결론으로 자연스럽게 이어진다.
불변 객체는 그 자체로 실패 원자성을 제공한다.(아이템 76)
다시 말해 신뢰할 수 없는 하위 클래스의 인스턴스라고 확인되면, 이 인수들을 가변이라 가정하고 방어적으로 복사해 사용해야 한다.(아이템50)
지연 초기화(아이템 803의 예이기도 한 이 기법을 String도 사용한다.
String과 BigInteger처럼 무거운 값 객체도 불변으로 만들 수 있는지 고심해야한다. 성능 때문에 어쩔 수 없다면(아이템 67)불변 클래스와 쌍을 이루는 가변 동반 클래스를 public 클래스로 제공하도록 해야한다.
'IT 개발 > 개념 정리' 카테고리의 다른 글
[아이템 19] 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2022.05.21 |
---|---|
[아이템 18] 상속보다는 컴포지션을 사용하라 (0) | 2022.05.14 |
[아이템 16] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2022.05.14 |
[아이템 15] 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2022.05.13 |
[이펙티브 자바 3장] 모든 객체의 공통 메서드 (0) | 2022.05.02 |