を回避するためのいくつかの代替例をいくつか紹介しConcurrentModificationException
ます。
次の本のコレクションがあるとします
List<Book> books = new ArrayList<Book>();
books.add(new Book(new ISBN("0-201-63361-2")));
books.add(new Book(new ISBN("0-201-63361-3")));
books.add(new Book(new ISBN("0-201-63361-4")));
収集して削除
最初の手法は、削除するすべてのオブジェクトを収集すること(たとえば、拡張されたforループを使用すること)で構成され、反復が終了したら、見つかったすべてのオブジェクトを削除します。
ISBN isbn = new ISBN("0-201-63361-2");
List<Book> found = new ArrayList<Book>();
for(Book book : books){
if(book.getIsbn().equals(isbn)){
found.add(book);
}
}
books.removeAll(found);
これは、実行する操作が「削除」であると想定しています。
このアプローチも「追加」したい場合も機能しますが、別のコレクションを繰り返し処理して、2番目のコレクションに追加する要素を決定addAll
し、最後にメソッドを発行するとします。
ListIteratorの使用
リストを使用しListIterator
ている場合、別の手法は、反復処理中にアイテムの削除と追加をサポートするを使用することです。
ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
if(iter.next().getIsbn().equals(isbn)){
iter.remove();
}
}
繰り返しますが、上の例では「remove」メソッドを使用しましたが、これはあなたの質問が示唆しているように思われますが、そのadd
メソッドを使用して、反復中に新しい要素を追加することもできます。
JDKの使用> = 8
Java 8以上のバージョンを使用している人のために、Java 8を利用するために使用できる他の方法がいくつかあります。
基本クラスremoveIf
で新しいメソッドを使用できますCollection
。
ISBN other = new ISBN("0-201-63361-2");
books.removeIf(b -> b.getIsbn().equals(other));
または、新しいストリームAPIを使用します。
ISBN other = new ISBN("0-201-63361-2");
List<Book> filtered = books.stream()
.filter(b -> b.getIsbn().equals(other))
.collect(Collectors.toList());
この最後のケースでは、コレクションから要素をフィルタリングするために、元の参照をフィルター処理されたコレクションに再割り当てする(つまりbooks = filtered
)か、フィルター処理されたコレクションを使用removeAll
して元のコレクションから見つかった要素に(つまりbooks.removeAll(filtered)
)します。
サブリストまたはサブセットを使用
他の選択肢もあります。リストがソートされていて、連続する要素を削除したい場合は、サブリストを作成してからクリアできます。
books.subList(0,5).clear();
サブリストは元のリストに基づいているため、これはこの要素のサブコレクションを削除する効率的な方法です。
NavigableSet.subSet
メソッドを使用してソートされたセット、またはそこで提供されているスライス方法のいずれかを使用すると、同様のことが実現できます。
考慮事項:
どの方法を使用するかは、何をしようとしているのかによって異なる場合があります。
- 収集と
removeAl
手法は、任意のコレクション(コレクション、リスト、セットなど)で機能します。
ListIterator
指定ListIterator
された実装が追加および削除操作のサポートを提供する場合、この手法は明らかにリストでのみ機能します。
- この
Iterator
アプローチはどのタイプのコレクションでも機能しますが、削除操作のみをサポートします。
ListIterator
/ Iterator
近づい明らかな利点は、我々が我々反復として削除ので、何かをコピーする必要がされていません。したがって、これは非常に効率的です。
- JDK 8ストリームの例では実際には何も削除されていませんが、目的の要素を探してから、元のコレクション参照を新しいものに置き換え、古いものをガベージコレクションしました。したがって、コレクションに対して繰り返し処理を行うのは1回だけであり、効率的です。
- 収集と
removeAll
アプローチの欠点は、2回繰り返す必要があることです。最初にfoor-loopで反復して、削除基準に一致するオブジェクトを探します。オブジェクトが見つかったら、元のコレクションから削除するように要求します。これは、このアイテムを探すための2回目の反復作業を意味します。それを除く。
Iterator
インターフェースのremoveメソッドがJavadocsで「オプション」としてマークされていることは言及する価値があると思います。つまり、removeメソッドを呼び出すIterator
とスローされる実装が存在する可能性があるということUnsupportedOperationException
です。したがって、要素の削除に対するイテレータのサポートを保証できない場合、このアプローチは他のアプローチよりも安全性が低いと思います。