要約:クイックフィックス
java.lang.UnsupportedOperationException は、通常、固定サイズまたは不変(immutable)のリストに対して要素を追加または削除しようとしたときに発生します。最も手っ取り早い解決策は、既存のリストを新しい ArrayList でラップすることです。
// これの代わりに(変更時に例外が発生します):
List<String> list = Arrays.asList("A", "B", "C");
// こうします(変更可能なコピーを作成します):
List<String> mutableList = new ArrayList<>(Arrays.asList("A", "B", "C"));
mutableList.add("D"); // これで動作します!
根本原因の特定
Java では、すべてのリストが同じように作られているわけではありません。すべてのリストが List インターフェースを実装していますが、基盤となる実装によって変更可能かどうかが決まります。java.lang.UnsupportedOperationException は、特定のリスト実装がサポートしていないメソッド(add()、remove()、または clear() など)を呼び出したときにスローされます。
一般的な原因 1: Arrays.asList()
Arrays.asList("項目1", "項目2") を使用すると、固定サイズのリストが返されます。このリストは元の配列を基盤としています。set() を使用して既存の要素の値を変更することはできますが、リストのサイズを変更することはできません。add() や remove() はサイズを変更するため、例外がスローされます。
List<String> items = Arrays.asList("りんご", "バナナ");
items.set(0, "アプリコット"); // これは問題ありません
items.add("チェリー"); // java.lang.UnsupportedOperationException をスローします
一般的な原因 2: List.of() (Java 9 以降)
Java 9 で導入された List.of() は、完全に不変(immutable)なリストを作成します。Arrays.asList() とは異なり、set() を使用して既存の値を変更することすらできません。リストを何らかの形で変更しようとすると、エラーが発生します。
List<String> items = List.of("りんご", "バナナ");
items.set(0, "オレンジ"); // java.lang.UnsupportedOperationException をスローします
items.add("チェリー"); // java.lang.UnsupportedOperationException をスローします
一般的な原因 3: Collections.unmodifiableList()
ライブラリやコードの他の部分から、変更を防ぐためにラップされたリストを受け取ることがあります。これは、内部データ構造を保護するための一般的なパターンです。
信頼できる解決方法
1. 変更可能なコピーを作成する(推奨)
最も堅牢な解決策は、固定サイズまたは不変のリストを java.util.ArrayList のコンストラクタに渡すことです。これにより、同じ要素を含む完全に新しいリストが作成されますが、標準的な動的配列の全機能を利用できるようになります。
List<String> fixedList = Arrays.asList("1", "2");
List<String> workingList = new ArrayList<>(fixedList);
workingList.add("3");
workingList.remove("1");
2. Java 8 Stream API を使用する
ストリームを使用してデータを処理し、結果のリストを確実に変更可能にしたい場合は、デフォルトの Collectors.toList()(Java のバージョンや実装によっては不変リストを返す場合があります)の代わりに Collectors.toCollection(ArrayList::new) を使用します。
List<String> mutableList = someDataSource.stream()
.filter(s -> s.startsWith("A"))
.collect(Collectors.toCollection(ArrayList::new));
3. Java 7 以前の適切な初期化
モダンなヘルパーメソッドを使用していない場合は、予期しない事態を避けるために古典的な初期化方法に従ってください:
List<String> list = new ArrayList<String>();
list.add("A");
list.add("B");
確認手順
修正が機能していることを確認するには、リスト作成の直後に簡単な変更テストを行ってください。以下のコードがクラッシュせずに実行されれば、リストは変更可能です:
try {
List<String> myTestList = // ... リスト作成ロジック
myTestList.add("テスト要素");
myTestList.remove("テスト要素");
System.out.println("成功: リストは変更可能です。");
} catch (UnsupportedOperationException e) {
System.err.println("失敗: リストは依然として不変または固定サイズです!");
}
重要なポイント
- **Arrays.asList** は固定サイズです(`set` はサポートしますが、`add/remove` はサポートしません)。
- **List.of** は厳格に不変です(一切の変更をサポートしません)。
- **ArrayList** のコンストラクタは、制限されたリストを作業可能なリストに変換するための最良の方法です。
- サードパーティ API が返すリストを変更することを想定しているかどうか、常にドキュメントを確認してください。

