자바 List add UnsupportedOperationException 원인과 해결
list.add(...) 한 줄에서 java.lang.UnsupportedOperationException이 난다면, 그 List가 크기가 고정됐거나 수정 불가(immutable)인 List이기 때문입니다. 원인은 대개 셋 중 하나입니다. ① Arrays.asList(...)로 만든 고정 크기 리스트, ② List.of(...)·Collections.unmodifiableList(...)·Collectors.toUnmodifiableList()로 만든 수정 불가 리스트, ③ Java 16부터 추가된 Stream.toList()(이것도 수정 불가)입니다. 해결은 수정 가능한 리스트로 감싸는 것 — new ArrayList<>(원본) 한 줄이면 됩니다. 아래에서 각각을 실제 실행 결과와 함께 정리합니다. (기준: JDK 21에서 직접 실행)
왜 add()에서 UnsupportedOperationException이 날까
List는 인터페이스일 뿐이고, 실제 동작은 뒤에 있는 구현체가 결정합니다. new ArrayList<>()처럼 크기를 늘릴 수 있는 리스트만 add()가 동작하고, 팩토리 메서드가 돌려주는 고정 크기·수정 불가 리스트는 add()·remove() 같은 변경 메서드를 지원하지 않는다고 명시합니다.
공식 문서(Java SE 21)가 이 동작을 그대로 못박아 뒀습니다.
UnsupportedOperationException to be thrown."Arrays.asList — "Returns a fixed-size list backed by the specified array."
즉 이 예외는 버그가 아니라 설계된 동작입니다. "이 리스트는 크기를 못 바꾼다"는 뜻이죠.
어떤 List가 수정 불가인가 — 한눈에 보는 표
아래는 각 리스트에서 add("c"), set(0, "x")를 호출했을 때 결과입니다. JDK 21에서 직접 실행한 값입니다.
| 만든 방법 | add() | set() |
|---|---|---|
new ArrayList<>(...) |
✅ 됨 | ✅ 됨 |
Arrays.asList(...) |
❌ 예외 | ✅ 됨 |
List.of(...) |
❌ 예외 | ❌ 예외 |
Collections.unmodifiableList(...) |
❌ 예외 | ❌ 예외 |
Collectors.toList() |
✅ 됨 | ✅ 됨 |
Stream.toList() (Java 16+) |
❌ 예외 | ❌ 예외 |
Collectors.toUnmodifiableList() |
❌ 예외 | ❌ 예외 |
가장 헷갈리는 함정 — Arrays.asList는 set은 되고 add는 안 된다
Arrays.asList()가 돌려주는 리스트는 "수정 불가"가 아니라 "크기 고정(fixed-size)"입니다. 배열을 그대로 감싼 뷰라서, 기존 자리의 값을 바꾸는 set()은 되지만, 크기가 변하는 add()·remove()는 예외가 납니다.
List<String> list = Arrays.asList("a", "b");
list.set(0, "x"); // ✅ OK — 배열 자리값 교체
list.add("c"); // ❌ UnsupportedOperationException
list.remove(0); // ❌ UnsupportedOperationException
반면 List.of()는 완전히 불변이라 set()조차 예외가 납니다. "왜 어떤 건 set이 되고 어떤 건 안 되지?"의 답이 여기 있습니다.
Stream.toList()와 Collectors.toList()의 차이 (버전 함정)
스트림을 리스트로 모을 때 두 방법의 수정 가능 여부가 다릅니다. 이게 버전별 함정입니다.
// 수정 가능한 ArrayList를 돌려줌
List<String> a = stream.collect(Collectors.toList());
a.add("c"); // ✅ OK
// Java 16부터 추가 · 수정 불가 리스트를 돌려줌
List<String> b = stream.toList();
b.add("c"); // ❌ UnsupportedOperationException
.toList()로 바꿨다가, 나중에 그 리스트에 add()를 하면 예외가 납니다. 모은 뒤에 원소를 더 넣을 계획이면 Collectors.toList()를 쓰거나, 아래처럼 새 ArrayList로 감싸세요.
해결 — 수정 가능한 리스트로 감싸기
고정·불변 리스트를 그대로 고치려 하지 말고, 내용을 복사한 새 ArrayList를 만들면 됩니다. 원본이 무엇이든 통합니다.
// ❌ 예외
List<String> list = Arrays.asList("a", "b");
list.add("c");
// ✅ 해결 — 수정 가능한 새 리스트로 감싼다
List<String> list = new ArrayList<>(Arrays.asList("a", "b"));
list.add("c"); // OK
// Stream 결과도 마찬가지
List<String> list = new ArrayList<>(stream.toList());
list.add("c"); // OK
배열에서 시작한다면 new ArrayList<>(List.of(arr))나 new ArrayList<>(Arrays.asList(arr)) 둘 다 됩니다.
자주 묻는 질문 (FAQ)
Q. Arrays.asList로 만든 리스트에 왜 set은 되나요?
배열을 감싼 고정 크기 뷰라서 크기만 못 바꿀 뿐, 기존 자리의 값 교체(set)는 배열에 그대로 반영됩니다. 크기가 바뀌는 add·remove만 막힙니다.
Q. List.of()와 Collections.unmodifiableList()는 뭐가 다른가요?
List.of()는 그 자체가 독립된 불변 리스트입니다. Collections.unmodifiableList()는 원본 리스트를 감싼 읽기 전용 뷰라서, 원본을 다른 참조로 바꾸면 뷰에도 반영됩니다. 둘 다 뷰/리스트에 직접 add()하면 예외가 납니다.
Q. List.of()는 null을 넣을 수 있나요?
아니요. List.of() 계열은 null 원소를 허용하지 않아, null을 넣으면 NullPointerException이 납니다(공식 문서 명시).
마무리
정리하면, add()에서 UnsupportedOperationException이 나는 건 그 리스트가 고정 크기(Arrays.asList)이거나 불변(List.of·unmodifiableList·toUnmodifiableList·Stream.toList)이기 때문입니다. 원소를 더 넣어야 하면 new ArrayList<>(원본)으로 감싸서 쓰면 됩니다. 동작이 헷갈릴 땐 위 표를 기준 삼으세요. (버전에 따라 다를 수 있으니, 본문은 JDK 21 기준으로 검증했습니다.)
📚 참고 출처 (2026년 7월 20일 확인)
· Arrays (Java SE 21 & JDK 21) — asList
· List (Java SE 21 & JDK 21) — Unmodifiable Lists
· 본문 표·코드의 동작은 JDK 21.0.1로 직접 실행해 확인

COMMENTS