for-eachループを使用してコレクションを反復処理しながらコレクションを変更すると、が得られConcurrentModificationException
ます。回避策はありますか?
4 に答える
を使用しIterator#remove
ます。
これは、反復中にコレクションを変更する唯一の安全な方法です。詳細については、コレクションインターフェイスのチュートリアルを参照してください。
反復中に要素を追加する機能も必要な場合は、を使用してListIterator
ください。
回避策の 1 つは、変更を保存し、ループ後に追加/削除することです。
例えば:
List<Item> toRemove = new LinkedList<Item>();
for(Item it:items){
if(remove){
toRemove.add(it);
}
}
items.removeAll(toRemove);
2 番目の回避策は、反復子が例外を発生させないコレクション クラスを使用することです。たとえばConcurrentLinkedQueue
、ConcurrentHashMap
などです。
これらは、反復子の一貫性のより弱いモデルを提供することにより、例外をスローする必要を回避します。(もちろん、これらのモデルを理解し、アプリケーションに適しているかどうかを判断する必要があります。)
通常、これらは非同時コレクションよりも少し遅くなりますが、大きな競合がある場合は、同期コレクション ラッパーよりも高速です。
コレクションから要素を削除するだけの場合は、Iterable の代わりに Iterator を使用できます。
それ以外の場合、元のコレクションを反復するのではなく、最初にリストのコピーを作成することができます。たとえば、コレクションがリストの場合、新しい ArrayList(originaList) を作成してそれを反復処理できます。変更は元のリストに対して行う必要があります。
ユースケースに適した別の方法は、 for-each ではなく従来の for- を使用することです。