불변 객체에 대해 정리해보는 시간을 가져보도록 한다.
대부분의 내용은 이펙티브 자바와, 다른 분의 블로그를 인용하였습니다.
왜 불변 객체를 사용해야 할까?
- 불변 객체는 스레드의 안전하다.
- 생성과 동시에 값이 할당되고 변경이 불가능한 객체임으로 기본적으로 스레드의 안전하다.
- 실패 원자적인 메서드를 만들 수 있다.
- 이펙티브 자바에 따르면 메서드에서 예외가 발생한 후 에도 객체는 메서드 호출 전과 똑같은 유효한 상태이다. (내부 상태를 변경한 적이 없으니 이를 만족한다.
- 부수효과를 방지 할 수 있다.
- 객체 생성과 동시에 값이 할당되어 상태에 대한 변경이 내부에서도 이루어지지 않기 때문에 변경에 따른 부수효과를 방지할 수 있으며 이 부분은 사용시점에 가독성과 안정성을 향상한다.
- GC의 성능을 향상할 가능성이 있다.
- 불변 객체는 GC 대상을 Skip 할 수 있어 대상 탐색 시 성능상 유리하다고는 하는데 이 부분은 별도의 이해가 필요할 듯싶다.
단점은?
- 새로운 값이 필요할 때 새로운 객체를 생성해야 해서 이 부분에 메모리에 비효율성이 나타난다.
- 데이터가 한정적인 경우 객체를 미리 생성하는 전략(캐싱)으로 어느 정도 비효율을 막을 수 있다.
- LottoNumber을 미리 캐싱한다.
- 데이터가 한정적인 경우 객체를 미리 생성하는 전략(캐싱)으로 어느 정도 비효율을 막을 수 있다.
public class LottoNumber {
static final int MIN_NUMBER = 1;
static final int MAX_NUMBER = 45;
private static Map<Integer, LottoNumber> lottoNumbers = new HashMap<>();
private final int number;
static {
for (int i = MIN_NUMBER; i <= MAX_NUMBER; i++) {
lottoNumbers.put(i, new LottoNumber(i));
}
}
private LottoNumber(int number) {
this.number = number;
}
public static LottoNumber of(int number) {
LottoNumber lottoNumber = lottoNumbers.get(number);
if (lottoNumber == null) {
throw new IllegalArgumentException("로또의 숫자는" + MIN_NUMBER + "~" + MAX_NUMBER + "까지만 허용합니다.");
}
return lottoNumber;
}
작성법
불변 객체는 아래에 규칙에 맞추어 작성한다.
- 객체의 상태를 변경하는 메서드를 제공하지 않는다.
- 클래스를 확장할 수 없도록 한다.
- 모든 필드를 final로 선언한다.
- 모든 필드를 private으로 선언한다.
- 자신 외에는 내부의 가변 컴포넌트에 접근할 수 없도록 한다.
- setter를 선언하지 않는다.
작성 예시 코드
- 원시 타입만 있는 클래스
public class ImmutableData {
private final int data;
public ImmutableData(int data) {
this.data = data;
}
public int getData() {
return data;
}
}
- 참조 타입이 있는 클래스 (예시 컬랙션)
public class ImmutableCollection {
private final List<String> data;
public ImmutableCollection(final List<String> data) {
this.data = List.copyOf(data);
}
public List<String> getData() {
return data;
}
//java 8
public List<String> getCollection() {
return Collections.unmodifiableList(data);
}
}
만약 Copy of가 없다면 컬랙션을 조회하고 add함수를 통해 값을 변경할 수 있음으로 이를 막기 위해 CopyOf 혹은 get 메서드에 Collections.unmodifiableList로 선언해둔다.
결론
오라클 공식문서에 따르면 “불변 객체는 당신이 고민하면서 만든 가변 객체보다 메모리를 더 효율적으로 적게 사용한다.”라고 한다.
그만큼 불변 객체가 충분히 적용할 수 있는 부분이라면 적극 적용하면 좋을 거 같다.
이펙티브 자바 아이템 17 항목처럼 적용이 불가능하다면 변경 가능서울 최소화 하는 편이 좋을 것 같다.
- 참조 문서
- 이펙티브 자바 (Item 17)http://www.yes24.com/Product/Goods/65551284
- 망나니개발자님 블로그 https://mangkyu.tistory.com/131