본문은 Effective Java를 읽고 간단하게 정리한 글입니다. 필요에 따라 생략/수정된 부분이 있을 수 있으며, 내용이 추후 변경될 수 있습니다.
선결론
- 클래스는 꼭 필요한 경우 외엔 불변이어야 한다
- 모든 클래스를 불변으로 만드는 것은 사실상 불가능하므로 가변 클래스라도 변경할 수 있는 부분을 최소한으로 줄여야 한다
- 즉, 다른 합당한 이유가 없다면 모든 필드는 private final이어야 한다
- 생성자는 불변식 설정이 모두 완료된, 초기화가 완벽히 끝난 상태의 객체를 생성해야 한다
불변 클래스의 장단점
장점
- 단순하다
- 가변 객체보다 부수효과에서 자유롭기 때문에 사용하기 쉽다
- 스레드 안전하고 따로 동기화할 필요가 없다
- 즉, 불변 객체는 자유롭게 공유할 수 있다
- 이때, 불변 클래스의 인스턴스는 정적 팩터리(아이템1)를 사용하여 최대한 재활용하는 것을 권장한다
- 방어적 복사가 필요없다
- 따라서 clone 메서드나 복사 생성자(아이템 13)를 제공하지 않는 게 좋다
- 불변 객체 간에 내부 데이터를 공유할 수 있다
- 객체를 만들 때 다른 불변 객체를 구성요소로 사용하면 이점이 많다
- 객체의 필드가 불변이라면 불변식을 유지하기 수월하다
- 실패 원자성을 제공한다
- 실패 원자성이란? 메서드에서 예외가 발생한 후에도 객체가 (메서드 호출 전과 동일하게) 유효한 상태인 것
단점
- 객체를 생성하는 데 비용이 큰 경우에 성능 저하가 일어날 수 있다
- 값이 다르면 반드시 독립된 객체로 만들어야 하기 때문이다
- 이때, 고성능의 연산을 요구하는 작업 수행 시에 불필요한 객체 생성을 막아주기 위해 내부적으로 가변 동반 클래스(e.g. StringBuilder)를 사용할 수 있다
불변 클래스 만드는 방법
- 객체의 상태를 변경하는 메서드(변경자)를 제공하지 않는다
- 대신 (새로운 상태를 지닌) 새로운 인스턴스를 반환하게끔 구현한다
- 클래스를 확장할 수 없도록 한다
- 클래스를 final로 선언한다
- 모든 생성자를 private 혹은 package-private으로 만들고 public 정적 팩터리를 제공한다 → 이쪽이 좀 더 유연하다
- 모든 필드를 final로 선언한다
- 설계자의 의도를 명확히 드러낸다
- 스레드 안전성을 제공하고 별도의 동기화가 필요없게끔 한다
- 모든 필드를 private로 선언한다
- 클라이언트가 가변 객체를 참조하는 필드에 직접 접근해 수정하는 일을 막아준다
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다
- 가변 객체를 참조하는 필드가 있을 때, 클라이언트가 해당 객체의 참조를 얻을 수 없도록 해야 한다
- 생성자, 접근자, readObject 메서드 모두에서 방어적 복사를 수행
'책 > Effective Java' 카테고리의 다른 글
[이펙티브 자바] 아이템 19: 상속을 고려해 설계하고 문서화하라. 그러지 않았다면 상속을 금지하라 (0) | 2022.05.05 |
---|---|
[이펙티브 자바] 아이템 18: 상속보다는 컴포지션을 사용하라 (0) | 2022.05.05 |
[이펙티브 자바] 아이템 16: public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 (0) | 2022.05.02 |
[이펙티브 자바] 아이템15: 클래스와 멤버의 접근 권한을 최소화하라 (0) | 2022.04.28 |
[이펙티브 자바] 아이템14: Comparable을 구현할지 고려하라 (0) | 2022.04.27 |