1

マップに整数キーが含まれ、その値として文字列のリストがあるとします。次に、私はこれを行うことはできません:

for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
    for (String string : entry.getValue()){
        if (string.startsWith("a")){
           entry.getValue().remove(string);
        }
    }
}

投げConcurrentModificationExceptionます。しかし、私が次のことをすると:

for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
    entry.setValue(new ArrayList<String>());
}

これは完全に機能します。今でも基になるマップを変更していませんか?

4

2 に答える 2

7

問題はMap、値リストを使用している方法とは関係ありません。以下はいずれかで失敗しますArrayList

for (String string : list){
    if (string.startsWith("a")){
       list.remove(string);
    }
}

この理由は、次のJavadocで説明されていArrayListます。

このクラスのイテレータメソッドとlistIteratorメソッドによって返されるイテレータはフェイルファストです。イテレータの作成後にリストが構造的に変更された場合、イテレータ自体のremoveまたはaddメソッド以外の方法で、イテレータはConcurrentModificationExceptionをスローします。したがって、同時変更に直面した場合、イテレータは、将来の不確定な時点で任意の非決定的な動作のリスクを冒すのではなく、迅速かつクリーンに失敗します。

(言い換えると、リストから要素を削除すると、イテレータは基になる配列の正しいインデックスを指していない可能性があります。したがって、破損している可能性のあるイテレータを使用できるようにする代わりにConcurrentModificationException、礼儀としてをスローします。プログラムを再設計する必要があることを通知します。)

簡単な修正は使用することです

Iterator<String> itr = entry.getValue().iterator();
while (itr.hasNext()) {
  if (itr.next().startsWith("a")) {
    itr.remove();
  }
}
于 2012-08-13T16:48:48.300 に答える
3

HashMap.java の entrySet() の Javadoc を参照してください。理由がわかります。

ドキュメントから:

このマップに含まれるマッピングの Set ビューを返します。セットはマップに支えられているため、マップへの変更はセットに反映され、その逆も同様です。セットに対する反復の進行中にマップが変更された場合 (反復子自体の削除操作、または反復子によって返されたマップ エントリに対する setValue 操作による場合を除く)、反復の結果は未定義です。セットは、Iterator.remove、Set.remove、removeAll、retainAll、および clear オペレーションを介して、マップから対応するマッピングを削除する要素の削除をサポートします。add または addAll 操作はサポートされていません。

指定方法: Map の entrySet()、

オーバーライド: AbstractMap の entrySet()

戻り値: このマップに含まれるマッピングのセット ビュー

于 2012-08-13T16:43:20.387 に答える