1. ホーム
  2. java

[解決済み] この例では、なぜ java.util.ConcurrentModificationException が発生しないのですか?

2022-04-20 21:51:39

質問

注:私が意識しているのは Iterator#remove() メソッドを使用します。

以下のコードサンプルでは、なぜか List.removemain メソッドが投げます。 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);
            }
        }
    }
}

解決方法は?

その理由はこうだ。 Javadocに書いてある通りです。

このクラスのイテレータと listIterator が返すイテレータは メソッドはフェールファストです。 イテレータが作成された後、そのイテレータを使用する以外の何らかの方法で イテレータ自身の remove メソッドや add メソッドを使用すると、イテレータは ConcurrentModificationException。

このチェックは next() というメソッドがあります (スタックトレースで確認できます)。しかし、私たちが到達するのは 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番目の要素を削除します。