MeWrite Docs

Java: ConcurrentModificationException

Javaでコレクションをイテレート中に変更した際のエラー原因と解決策

概要

コレクションをイテレート中に構造を変更した際に発生するエラーです。

エラーメッセージ

``` java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) at java.util.ArrayList$Itr.next(ArrayList.java:851) ```

原因

  1. for-eachループ中の変更: 拡張forループでadd/remove
  2. マルチスレッドアクセス: 別スレッドからの変更
  3. ネストしたイテレーション: 内側で外側のコレクションを変更
  4. Streamでの変更: Stream処理中の元コレクション変更

解決策

1. Iterator.remove()を使用

```java List list = new ArrayList<>(Arrays.asList(“a”, “b”, “c”));

// 悪い例 for (String item : list) { if (item.equals(“b”)) { list.remove(item); // ConcurrentModificationException } }

// 良い例 Iterator iterator = list.iterator(); while (iterator.hasNext()) { String item = iterator.next(); if (item.equals(“b”)) { iterator.remove(); // OK } } ```

2. removeIfを使用 (Java 8+)

```java list.removeIf(item -> item.equals(“b”)); ```

3. 新しいコレクションを作成

```java List toRemove = new ArrayList<>(); for (String item : list) { if (item.equals(“b”)) { toRemove.add(item); } } list.removeAll(toRemove);

// または Stream List filtered = list.stream() .filter(item -> !item.equals(“b”)) .collect(Collectors.toList()); ```

4. ConcurrentHashMapを使用

```java // マルチスレッド環境 Map<String, Integer> map = new ConcurrentHashMap<>();

// for-eachでも安全 for (Map.Entry<String, Integer> entry : map.entrySet()) { if (entry.getValue() < 0) { map.remove(entry.getKey()); // OK(弱い一貫性) } } ```

5. CopyOnWriteArrayListを使用

```java List list = new CopyOnWriteArrayList<>();

// 読み取りが多く、書き込みが少ない場合に有効 for (String item : list) { if (item.equals(“b”)) { list.remove(item); // OK(コピーが作成される) } } ```

よくある間違い

  • synchronizedでラップすれば安全と思い込む
  • インデックスベースのforループでも発生する場合がある
  • fail-fastの仕組みを理解していない

関連エラー

関連エラー

Java の他のエラー

最終更新: 2025-12-10