CATEGORY

카테고리 (607)
AI (12)
Language & Specs (259)
FrameWork (34)
Library (19)
App (41)
Git (8)
Build & Dependency (2)
AWS (15)
DataBase (45)
OS (33)
Tool (16)
IT (120)
반응형
SEEMINGLY ONLINE

Seemingly
Online

이모저모 방방곡곡 두루두루 개발지식 저장소

RECENT POSTS

Language & Specs/Java

자바 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)가 이 동작을 그대로 못박아 뒀습니다.

💡 List.of / List.copyOf (Unmodifiable Lists) — "They are unmodifiable. Elements cannot be added, removed, or replaced. Calling any mutator method on the List will always cause 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