For-eachループを使用して反復処理中にCollectionを変更すると、ConcurrentModificationException
が返されます。回避策はありますか?
使用する - Iterator#remove
。
これは、反復中にコレクションを変更する唯一の安全な方法です。詳細については、「 コレクションインターフェイス チュートリアル」を参照してください。
反復中に要素をaddする機能も必要な場合は、 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-を使用することです。