개요
앞에서 작성한 Arrays.asList()와 List.of()를 얘기하며 Collections의 unmodifiableList()도 아주 짧게 서술했었다
이 글에서는 Collections의 unmodifiableList()가 왜 완벽한 불변이 아닌지 정리했던 내용을 작성해보려고 한다
Collections.unmodifiableList() 메소드는 인자로 받은 '리스트'를 불변 리스트로 반환하는 메소드이다.
반환된 리스트에 add, remove, set, clear을 수행하면 UnsupportedOperationException 예외가 발생한다.
이유는 unmodifiableList는 UnmodifiableCollection를 상속받고 있기 때문이다.

1. 왜 인자로 받은 리스트와 unmodifiableList는 연결되어 있는걸까?

이는 내부 로직을 보면 쉽게 이해할 수 있다.
인자로 받은 리스트를 그대로 UnmodifiableCollection의 생성자 인자로 넘겨주고 있다.
UnmodifiableCollection의 생성자를 보면 this.c = c;를 통해 필드 값을 설정해주고 있음을 알 수 있다.
즉, 리스트를 새롭게 생성하는 것이 아니라 참조값을 그대로 주는 것이다.
이는 참조값을 그대로 복사하는 것과 동일하기에 인자로 받은 리스트와 unmodifiable을 통해 생긴 리스트가 동일한 리스트임을 확인할 수 있다.
2. unmodifiableList가 불변이 아닌 예제
public static void main(String[] args) {
List<String> origin = new ArrayList<>();
origin.add("A");
origin.add("B");
origin.add("C");
origin.add("D");
origin.add("E");
origin.add("F");
List<String> unmodifiable = Collections.unmodifiableList(origin);
System.out.println("origin: " + origin);
System.out.println("unmodifiable: " + unmodifiable);
System.out.println();
System.out.println("====== origin update =====");
System.out.println();
origin.set(2, "S");
origin.set(3, "Y");
System.out.println("origin: " + origin);
System.out.println("unmodifiable: " + unmodifiable);
}

origin 리스트에 대한 2번째, 3번째 요소를 수정했다.
(C를 S로, D를 Y로)
하지만 출력 결과는 origin 리스트의 수정 사항이 unmodifiable에도 적용되어 값이 변하는 모습을 확인할 수 있다..
즉, 이것으로 unmodifiableList는 완벽하게 불변하지 않다는 것을 확인할 수 있다.
3. 그렇다면 완벽한 불변 리스트를 얻기위해선 어떻게 해야할까?
정말로 불변한 리스트를 얻기 위해서는 어떻게 해야할까?
가장 간단하겐 JDK 9버전부터 추가된 (인자 3개 이상, 전글 참조) List.of(a1, a2, a3)를 사용하면 된다.
하지만 아직까지 JDK 버전이 8이하라면 해당 방법을 사용할 수 없을 것이다. 그럴땐 아래와 같이 사용하면 된다.
아예 새로운 ArrayList를 생성하여 참조 값을 제거하고 동시에 새로운 ArrayList에 대해 추적하는 값(변수로 접근 불가능)이 없도록 하는 것이다.
(=익명 리스트를 인자로 주어라)
List<String> unmodifiable = Collections.unmodifiableList(new ArrayList<>(list));
또한, stream을 사용 후 마지막에 collect(Collectors.toUnmodifiableList())를 호출하는 것도 stream이 연산이 끝난 뒤 완전히 새로운 리스트를 반환하기 때문에 불변 리스트를 생성할 수 있다.
만약 JDK 16 이상을 사용한다면 toList()로 더욱 간단하게 불변 리스트를 생성할 수 있다.
결론 - unmodifiableList는 완벽한 불변이 아니다.
이유는 인자로 받은 리스트와 완전히 동일한 리스트이기 때문에 인자로 받은 리스트(=원본 리스트)가 변화하면 unmodifiableList도 변경될 수 있기 때문이다.
하지만 원본 리스트에에 대한 접근을 할 수 없게된다면 (=익명으로 원본 리스트를 넘겨준다면) 그땐 완벽한 불변으로 볼 수 있지도 않을까? 싶기도 했다.
만약 이런 경우 '리플렉션'을 통해 익명 리스트에 대해 값을 변경한다면 완벽하게 불변으로 볼 수는 없겠지만 ... 해당 글을 작성하며 예시를 든 예제보다는 더 불변하다고 볼 수는 있을 것 같다.
뭐든 상황에 맞추어 최대한 자유로이 활용하는 것이 더 중요하다고 느끼는 요즘이다.
번외 및 Reference )
[Java] UnmodifiableList는 진짜 불변 리스트가 아니다
목차 들어가기 전에 불변성이 강조되는 객체지향 프로그래밍의 특성상 자바에서도 UnmodifiableList라는 클래스가 존재한다(물론 List 뿐만 아니라 Map과 Set도 존재한다). UnmodifiableList라는 이름에 걸
colabear754.tistory.com
처음에는 참조한 이 포스팅 글이 이해가 되지 않았는데.. Arrays.asList를 정리하다보니 함께 이해할 수 있게 되었다.
역시 잘 모를땐 공식문서와 내부 코드를 보는 것이 가장 정확한 것 같다.
'Development Tools > Java' 카테고리의 다른 글
| [Java] Stream.forEach() 와 Collection.forEach() 비교하기 (0) | 2025.10.29 |
|---|---|
| [Java] Enum 비교는 == 일까 equals() 일까? (0) | 2025.10.22 |
| [Java] Arrays.asList로 반환되는 리스트는 고정 길이인 이유 | feat. List.of() (4) | 2025.05.18 |
| [Java] 객체 지향 설계 5원칙 - SOLID 원칙 (0) | 2024.04.19 |
| [Java] Java의 static 키워드는 상속이 불가능한 이유와 Hiding (0) | 2024.03.28 |