この例では java.util.ConcurrentModificationException が発生しないのはなぜですか? 質問する

この例では java.util.ConcurrentModificationException が発生しないのはなぜですか? 質問する

注: そのIterator#remove()方法は承知しております。

List.remove次のコードサンプルでは、 ​​inmainメソッドがなぜ をスローするのか分かりませんConcurrentModificationExceptionが、ない方法でremove

public class RemoveListElementDemo {    
    private static final List<Integer> integerList;

    static {
        integerList = new ArrayList<Integer>();
        integerList.add(1);
        integerList.add(2);
        integerList.add(3);
    }

    public static void remove(Integer toRemove) {
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }

    public static void main(String... args) {                
        remove(Integer.valueOf(2));

        Integer toRemove = Integer.valueOf(3);
        for(Integer integer : integerList) {
            if(integer.equals(toRemove)) {                
                integerList.remove(integer);
            }
        }
    }
}

ベストアンサー1

理由は次のとおりです。Javadoc に次のように記載されています。

このクラスの iterator メソッドと listIterator メソッドによって返される反復子はフェイルファーストです。反復子の作成後に、反復子の削除メソッドまたは追加メソッド以外の方法でリストの構造が変更された場合、反復子は ConcurrentModificationException をスローします。

このチェックは、next()イテレータのメソッドで行われます (スタック トレースで確認できます)。ただし、 true が返されたnext()場合にのみメソッドに到達しますhasNext()。これは、境界が満たされているかどうかを確認するために for each によって呼び出されるものです。remove メソッドでは、hasNext()別の要素を返す必要があるかどうかを確認するときに、2 つの要素が返されたことがわかります。1 つの要素が削除された後、リストには 2 つの要素のみが含まれます。これですべて順調で、反復処理は完了です。同時変更のチェックは行われません。これは、next()呼び出されることのないメソッドで行われるためです。

次に 2 番目のループに進みます。2 番目の数値を削除した後、hasNext メソッドは、さらに値を返すことができるかどうかを再度確認します。すでに 2 つの値が返されていますが、リストには 1 つしか含まれていません。ただし、ここでのコードは次のとおりです。

public boolean hasNext() {
        return cursor != size();
}

1 != 2 なので、next()メソッドを続行します。メソッドは、誰かがリストを操作したことを認識し、例外を発生させます。

あなたの質問が解決されたことを願います。

まとめ

List.remove()ConcurrentModificationExceptionリストから最後から 2 番目の要素を削除しても例外は発生しません。

おすすめ記事