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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?