Code Fix

中級

ConcurrentModificationException の原因と直し方

ループ中のリスト変更で発生します。removeIf、Iterator、逆順ループの3つの解法を比較します。

エラーメッセージの読み方

Exception in thread "main" java.util.ConcurrentModificationException
main
スレッド名 — mainなら起動直後の処理で発生しています
java.util
パッケージ — java.lang なら標準の基本例外です
ConcurrentModificationException
例外クラス — 何が起きたか。ここを検索するのが最短です

このエラーが出る典型パターン

パターン1

 1  import java.util.ArrayList;
 2  import java.util.List;
 3  
 4  public class Main {
 5      public static void main(String[] args) {
 6          List<String> list = new ArrayList<>(List.of("a", "b", "c", "d"));
 7          for (String s : list) if (s.equals("b")) list.remove(s);
                                        ^
 8          System.out.println(list);
 9      }
10  }
Exception in thread "main" java.util.ConcurrentModificationExceptionexited with code 1

拡張forで回している最中にリストを変更すると例外になります。removeIfかIteratorを使います。

直し方: for (String s : list) if (s.equals("b")) list.remove(s);list.removeIf(s -> s.equals("b")); にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  import java.util.ArrayList;
 2  import java.util.List;
 3  
 4  public class Main {
 5      public static void main(String[] args) {
 6          List<Integer> list = new ArrayList<>(List.of(1, 2, 3));
 7          for (int i = list.size()    ; i >= 0; i--) {
                                ^
 8              if (list.get(i) == 2) list.remove(i);
 9          }
10          System.out.println(list);
11      }
12  }
Exception in thread "main" java.lang.IndexOutOfBoundsExceptionexited with code 1

添字で削除するときは後ろから回します。前から削ると以降の要素が繰り上がって位置がずれます。

直し方: list.size()list.size() - 1 にします。

この問題を解いてみる →

パターン3

 1  import java.util.ArrayList;
 2  import java.util.List;
 3  
 4  public class Main {
 5      public static void main(String[] args) {
 6          List<String> list = List.of("a")                 ;
                                              ^
 7          list.add("x");
 8          System.out.println(list);
 9      }
10  }
Exception in thread "main" java.lang.UnsupportedOperationExceptionexited with code 1

List.ofは変更不可のリストを返します。追加や削除をするならArrayListに包み直します。

直し方: List.of("a")new ArrayList<>(List.of("a")) にします。

この問題を解いてみる →

よくある誤解

例外が出ないこともあります。最後から2番目の要素を削除すると検出をすり抜けるため、たまたま動いてしまいます。

まとめ

ConcurrentModificationExceptionは中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)