불변 객체란 인스턴스의 내부 값을 수정할 수 없는 객체를 말합니다.
불변 인스턴스의 정보는 생성되는 순간 고정되어 해당 객체가 소멸되는 순간까지 절대 달라지지 않습니다.
1. 객체의 상태를 변경하는 메서드를 제공하지 않는다.
2. 클래스를 확장할 수 없도록 한다.
3. 모든 필드를 final로 선언한다.
4. 모든 필드를 private로 선언한다.
5. 자신 외에는 내부 가변 컴포넌트에 접근할 수 없도록 한다.(방어적 복사)
변경이 이뤄질 것 같은 코드를 하나씩 보지 않아도 확인하지 않아도 되기 때문입니다. https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.htmlhttps://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html#distribution_lifetimespublic class Member {
// 가변 객체를 property 갖고 있음
private final Age age;
public Member(Age age) {
this.age = age;
}
public Age getAge() {
return age;
}
}
// 불변 객체가 아님
class Age {
private int value;
public Age(final int age) {
this.value = age;
}
public void setValue(final int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
불변 객체가 아닙니다.public class ImmutableTest {
@DisplayName("불변 객체에서 참조 타입(가변)이 있는 경우")
@Test
void immutableTest1() {
// given
Age age = new Age(10);
Member member = new Member(age);
System.out.println("before: " + member.getAge().getValue()); // 10
member.getAge().setValue(20);
System.out.println("after: " + member.getAge().getValue()); // 20
}
}
public class ArrayObject {
private final int[] array;
public ArrayObject(final int[] array) {
this.array = Arrays.copyOf(array, array.length);
}
public int[] getArray() {
return array == null ? null : array.clone();
}
}
하지만 원시 타입 배열이 아닌 객체 타입 배열의 경우 해당 객체는 불변 객체이어야 합니다.@DisplayName("Array의 경우 clone을 통해 불변을 유지할 수 있다.")
@Test
void immutableTest2() {
int[] array = {1, 2, 3};
ArrayObject arrayObject = new ArrayObject(array);
// 1, 2, 3
for (int number : arrayObject.getArray()) {
System.out.println("number = " + number);
}
array[0] = 123123123;
// 1, 2, 3
for (int number : arrayObject.getArray()) {
System.out.println("number = " + number);
}
}
public class ListObject {
private final List<Member> members;
public ListObject(final List<Member> members) {
this.members = new ArrayList<>(members);
}
public List<Member> getMembers() {
return Collections.unmodifiableList(members);
}
}
unmodifiable Collection을 사용하여 값을 변경할 경우 예외가 발생하여 직접 예외처리를 진행해야 합니다.@DisplayName("List의 경우 unmodifiableList 사용을 통해 불변을 유지할 수 있다.")
@Test
void immutableTest3() {
ArrayList<Member> members = new ArrayList<>();
members.add(new Member(new Age(10)));
ListObject listObject = new ListObject(members);
// 10
for (Member member : listObject.getMembers()) {
System.out.println("member.getAge().getValue() = " + member.getAge().getValue());
}
members.add(new Member(new Age(20)));
// 10
for (Member member : listObject.getMembers()) {
System.out.println("member.getAge().getValue() = " + member.getAge().getValue());
}
}