繰り返し処理時にArrayList中の要素を削除してもConcurrentModificationExceptionにならない場合(Java)
最近、仕事でJavaを使うことが多かったので、知識のまとめにもなると考えてJavaのSilverの試験を受験しようとしている。
曖昧な知識が整理されて勉強自体が知識の補強に役立っていると感じます。
勉強でこの本
を使っているが、その中の第4章「配列の使用と作成」の17と18の問題に、以下のようなプログラムがある。
その17番のプログラム(p.133)
public class Main {
public static void main(String args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for(String str: list) {
if("B".equals(str)) {
list.remove(str);
} else {
System.out.println(str);
}
}
}}
18番のプログラム(p.134)
public class Main {
public static void main(String args) {
ArrayList<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
list.add("D");
list.add("E");for(String str: list) {
if("C".equals(str)) {
list.remove(str);
}
}
for(String str: list) {
System.out.println(str);
}}
}
これらのプログラムをコンパイル、実行したときの結果として、正しいものを選べ、というのが設問である。
どちらのプログラムも、要素がString型のArrayList型の変数listを、拡張forループで処理している。条件に合致したときに、listから特定の要素をArrayListのremoveメソッドで削除している。
その場合、通常は繰り返し処理中にArrayListのremoveメソッドで要素を削除すると、ConcurrentModificationExceptionがthrowされる。
ArrayList (Java 2 Platform SE 5.0)
18のプログラムは、実行すると、実際にその例外がなげられる。
しかし、17のプログラムは実行してもConcurrentModificationExceptionがthrowされず、実行できてしまう。
これがなぜかわからなかった。
しかし、検索して調べてみて
この方のブログをみて納得した。
Listの最後から2番目の要素を削除すると、例外を投げることなく不正な状態で反復処理を終えてしまうそうです。
そのような、繰り返し処理中に要素を削除するようなこと自体が、言語の仕様を満たさない使用法なので、公式APIドキュメントにも言及がないらしいです。
繰り返し処理中に変更されるコレクションのことに関しては、以下の記事がわかりやすいと感じました。
MSC06-J. 繰り返し処理中に基となるコレクションを変更しない
ややこしいので、問題集にもこのことを一言書いてあるとありがたかったですが・・。
(問題集自体は非常にいい本で買ってよかったと思っています)
以上