Java 의 Collections.unmodifiableList 같은 API 를 이용해 List 같은 collection 을 변경 불가능하게 만들 수 있습니다. 그렇다면 이 API 를 사용하면 immutability 를 달성할 수 있을까요?
아니요. 불가능합니다. 물론 unmodifiableList
와 같은 컬렉션은 add
, remove
같은 컬렉션을 변경시키는 메서드들이 모두 막혀 있습니다. (호출하면 예외가 발생합니다.) 하지만 불변은 보장되지 않는데요, 우선 컬렉션의 요소들의 불변이 보장되지 않았기 때문입니다.
예를 들어, unmodifiableList
가 A와 B라는 두 객체를 요소로 가지고 있다고 하도록 하겠습니다. unmodifiableList
에 C를 새로 추가하거나, 리스트에서 B를 제거할 수는 없어서 불변같아 보이지만 A, B 객체가 불변 객체가 아니어서 A, B 객체의 내부 값이 바뀐다면, 리스트의 불변이 보장되지 않습니다.
불변이 보장되지 않는 또다른 이유로 unmodifiable collection들은 참조가 끊어지지 않는다는 문제가 있습니다. 이로 인해 컬렉션 내부 요소의 불변 뿐 아니라 컬렉션의 변경 불가능함
도 깨뜨릴 수 있습니다. 다음의 예시를 보겠습니다.
List<String> origin = new ArrayList<>();
origin.add("오찌");
List<String> unmodifiableList = Collections.unmodifiableList(origin);
origin.add("토르");
assertThat(unmodifiableList).containsOnly("오찌"); // ["오찌", "토르"]여서 실패
unmodifiableList
자체에는 요소를 추가, 삭제 등을 할 수 없지만, unmodifiableList의 원본 리스트에 요소를 추가하거나 삭제를 하게 되면 unmodifiableList에도 그 변경이 반영되게 됩니다. 이는 unmodifiableList를 만들 때, 원본 리스트의 요소를 복사해오는 것이 아니라 원본 리스트의 참조를 저장하기 때문입니다.
static class UnmodifiableList<E> extends UnmodifiableCollection<E> implements List<E> {
...
final List<? extends E> list;
UnmodifiableList(List<? extends E> list {
super(list);
this.list = list;
}
...
}