- JAVA
UnsupportedOperationExceptionの直し方|Java
java.lang.UnsupportedOperationException は、「変更できないリスト(やマップ)」に add・remove・put などをしたときの例外です。 一番多いのは、List.of() や Arrays.asList() で作ったリストに add したときです。
List<String> list = List.of("A", "B");
list.add("C"); // ← UnsupportedOperationException
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.ImmutableCollections.uoe(ImmutableCollections.java:142)
at java.base/java.util.ImmutableCollections$AbstractImmutableCollection.add(ImmutableCollections.java:147)
at St.main(St.java:2)
直し方は、変更できるリストにコピーしてから変更することです。
List<String> list = new ArrayList<>(List.of("A", "B"));
list.add("C"); // [A, B, C]
確認環境:OpenJDK 21.0.10(Linux)で再現しました(確認日 2026年10月12日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「UnsupportedOperationExceptionの直し方|Java」
スタックトレースの2行目で、どの作り方か分かる
例外のメッセージは空のことが多いので、at の2行目に出るクラス名で、リストの作り方を見分けます。
| スタックトレースに出るクラス | リストの作り方 |
|---|---|
java.util.ImmutableCollections |
List.of()・Set.of()・Map.of()・List.copyOf()・Stream.toList() |
java.util.AbstractList.add |
Arrays.asList() |
java.util.Collections$UnmodifiableCollection |
Collections.unmodifiableList() など |
Arrays.asList() に add したときのスタックトレースです。
Exception in thread "main" java.lang.UnsupportedOperationException
at java.base/java.util.AbstractList.add(AbstractList.java:155)
at java.base/java.util.AbstractList.add(AbstractList.java:113)
at St2.main(St2.java:2)
作り方ごとの、できる操作・できない操作(Java 21 で確かめた一覧)
| 作り方 | add |
remove |
set |
備考 |
|---|---|---|---|---|
List.of(...) |
例外 | 例外 | 例外 | null を入れると NullPointerException |
Arrays.asList(...) |
例外 | 例外 | できる | 長さは変えられない。set は元の配列も変わる |
stream.toList()(Java 16〜) |
例外 | 例外 | 例外 | |
stream.collect(Collectors.toList()) |
できる | できる | できる | 変更できるかは仕様では保証されていない |
Collections.unmodifiableList(...) |
例外 | 例外 | 例外 | 元のリストの変更は見える |
Collections.emptyList() |
例外 | 例外 | 例外 | |
new ArrayList<>(...) |
できる | できる | できる | 変更したいときはこれ |
マップ・セットも同じです。
| 作り方 | 例外になる操作 |
|---|---|
Map.of(...) |
put、remove、既にあるキーへの putIfAbsent も例外 |
Set.of(...) |
add、remove |
直し方① new ArrayList / new HashMap でコピーする
変更したいリストは、最初から new ArrayList<>() で作るか、コピーしてから変更します。
// リスト
List<String> list = new ArrayList<>(List.of("A", "B"));
list.add("C"); // [A, B, C]
// 配列から
List<String> fromArray = new ArrayList<>(Arrays.asList(array));
// Stream から(変更するなら toList() ではなくこちら)
List<String> names = users.stream()
.map(User::name)
.collect(Collectors.toCollection(ArrayList::new));
// マップ
Map<String, Integer> map = new HashMap<>(Map.of("a", 1));
map.put("b", 2);
Collectors.toList() は手元では変更できましたが、Javadoc に「返されるリストの型、可変性…は保証されない」とあります。 変更する前提なら、Collectors.toCollection(ArrayList::new) と書いて意図をはっきりさせるのが安全です。
直し方② Arrays.asList は「長さを変えない」ときだけ使う
Arrays.asList() は、元の配列の上に乗った「長さが固定のリスト」です。 要素の差し替え(set)はできますが、元の配列も一緒に変わりました。
String[] arr = {"A", "B"};
List<String> view = Arrays.asList(arr);
view.set(0, "Z");
System.out.println(Arrays.toString(arr)); // [Z, B] ← 配列も変わる
view.add("C"); // ← UnsupportedOperationException
removeIf も、消す要素があると例外、無いと例外になりませんでした。 テストで消す対象が無いデータだけを使うと気づかないので注意します。
List<String> l = Arrays.asList("A", "B");
l.removeIf(s -> s.equals("Z")); // false が返る(例外なし)
l.removeIf(s -> s.equals("A")); // UnsupportedOperationException: remove
直し方③ メソッドが返したリストは、変更しない前提で扱う
ライブラリや自分のメソッドが List.of() や toList() で返したリストを、受け取った側が add して例外になるのもよくある形です。
List<String> result = service.findNames(); // 中で .toList() している
result.add("追加"); // ← 例外
| 対処 | 書き方 |
|---|---|
| 受け取った側でコピーする | var names = new ArrayList<>(service.findNames()); |
| 返す側で変更できるリストを返す | .collect(Collectors.toCollection(ArrayList::new)) |
| 変更できないことを決まりにする | 戻り値のJavadocに「変更不可」と書く |
チームで決めるなら、「戻り値のリストは変更しない。変更したい側がコピーする」に揃えると、どこで例外になるかが読みやすくなります。
unmodifiableList と List.copyOf の違い
どちらも変更できないリストですが、元のリストを変えたときの見え方が違いました。
List<String> src = new ArrayList<>(List.of("A", "B", "C"));
List<String> view = Collections.unmodifiableList(src);
List<String> copy = List.copyOf(src);
src.add("D");
System.out.println(view); // [A, B, C, D] ← 元の変更が見える
System.out.println(copy); // [A, B, C] ← コピーなので変わらない
Collections.unmodifiableList |
List.copyOf |
|
|---|---|---|
| 中身 | 元のリストへの「読み取り専用の窓」 | 別のリスト(コピー) |
| 元を変えると | 見える | 見えない |
| null を含むリスト | そのまま | NullPointerException |
外に渡したあと中身が変わってほしくないなら List.copyOf が向いています。
List.of は null も入れられない
List.of() 系は、変更できないだけでなく、null を入れると NullPointerException でした。contains(null) も NullPointerException になります。
List.of("A", null); // NullPointerException
List.of("A").contains(null); // NullPointerException
null を含む可能性があるデータは、new ArrayList<>() に入れて扱います。
よくある質問
Q. メッセージが空で、どこが原因か分かりません。
A. スタックトレースの at のうち、自分のクラス名が出ている行が、変更しようとした場所です。その変数がどこで作られたかをたどり、List.of・Arrays.asList・toList() を探します。
Q. Arrays.asList で作ったリストに remove したら、メッセージが remove でした。
A. 同じ原因です。Arrays.asList は長さを変えられないため、remove も例外になります。new ArrayList<>(Arrays.asList(...)) にコピーします。
Q. ループ中の削除で ConcurrentModificationException が出ます。
A. それは変更できるリストを、拡張for文の途中で変更したときの別の例外です。関連記事「ConcurrentModificationExceptionの原因と対処法」で扱っています。
Q. 変更できないリストを使う良さは何ですか。
A. 受け取った側が勝手に中身を変えられないので、思わぬ書き換えを防げます。定数や戻り値には List.of・List.copyOf を使い、変更する処理の中だけ ArrayList を使う、と分けると扱いやすくなります。
Q. List.of と Arrays.asList の違いをもっと知りたい。
A. 関連記事「Java List.ofとArrays.asListの違い|変更可否の比較表」で扱っています。
まとめ
- 変更できないリスト・マップに
add・remove・putをしたときの例外 - スタックトレースに
ImmutableCollectionsならList.of系、AbstractList.addならArrays.asList - 直し方は
new ArrayList<>(...)・new HashMap<>(...)にコピーしてから変更 stream.toList()も変更できない。変更するならCollectors.toCollection(ArrayList::new)Arrays.asListはsetはできるが元の配列も変わる
参考・出典
確認日はいずれも 2026年10月12日です。
- Java SE 21 API「UnsupportedOperationException」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/UnsupportedOperationException.html
- Java SE 21 API「List」(Unmodifiable Lists):https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/List.html
- Java SE 21 API「Arrays.asList」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/Arrays.html
- Java SE 21 API「Collectors.toList」:https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/stream/Collectors.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「UnsupportedOperationExceptionの直し方|Java」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。