[解決済み】反復処理中にコレクションから要素を削除する
質問
AFAIKには、2つのアプローチがあります。
- コレクションのコピーに対して反復処理を行う
- 実際のコレクションのイテレータを使用する
例えば
List<Foo> fooListCopy = new ArrayList<Foo>(fooList);
for(Foo foo : fooListCopy){
// modify actual fooList
}
そして
Iterator<Foo> itr = fooList.iterator();
while(itr.hasNext()){
// modify actual fooList using itr.remove()
}
一方のアプローチを他方より好む理由はありますか(例えば、読みやすさの単純な理由で最初のアプローチを好むなど)?
どのように解決するのですか?
を回避するための代替案をいくつか挙げてみましょう。
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);
これは、行いたい操作が "delete" であると仮定した場合です。
もし、quot;add"したいのであれば、このアプローチも有効ですが、別のコレクションを繰り返し処理し、2番目のコレクションに追加したい要素を決定し、その後、quot; add"を発行すると仮定します。
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またはそれ以上のバージョンで作業する場合、それを利用するための他のテクニックがいくつかあります。
新しい
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
は、あらゆるコレクション(Collection、List、Setなど)で機能します。 -
その
ListIterator
のテクニックは、明らかにリストに対してのみ有効であり、与えられたListIterator
の実装は、追加と削除の操作をサポートしています。 -
は
Iterator
のアプローチは、どんなタイプのコレクションでも動作しますが、 remove操作しかサポートしていません。 -
を使用すると
ListIterator
/Iterator
のアプローチは、反復しながら削除していくので、何もコピーする必要がないのが明らかな利点です。つまり、これは非常に効率的なのです。 - JDK 8のストリームの例では、実際には何も削除せず、目的の要素を探してから、元のコレクション参照を新しいものに置き換え、古いものをガベージコレクションするようにしました。つまり、コレクションに対して一度だけ反復処理を行うので、効率的なのです。
-
コレクトと
removeAll
のアプローチでは、2回繰り返さなければならないのが欠点です。まず、foorループで削除基準に合致するオブジェクトを探し、それが見つかったら、元のコレクションから削除するように要求する。これは、削除するためにこのアイテムを探すという2回目の反復作業を意味する。 -
のremoveメソッドも、そのようなものであることは言うまでもないと思います。
Iterator
インターフェースは、Javadocs では "optional" としてマークされています。Iterator
を投げる実装があります。UnsupportedOperationException
remove メソッドを呼び出すと そのため、要素の削除に対するイテレータのサポートが保証されない場合、この方法は他の方法よりも安全性が低いと言えるでしょう。
関連
-
[解決済み] tempとは何ですか、またjavaにおけるtempの用途は何ですか?
-
[解決済み] Eclipse- Dynamic Web Module 3.0 で新しいプロジェクトを作成するときに Java 1.6 以降が必要なエラーが発生する。
-
[解決済み] 配列からArrayListを作成する
-
[解決済み] Java で、あるコンストラクタを別のコンストラクタから呼び出すにはどうすればよいですか?
-
[解決済み] Javaで文字列値からenum値を取得する方法
-
[解決済み] コレクションを反復処理し、ループ内でオブジェクトを削除する際に ConcurrentModificationException を回避する。
-
[解決済み] 反復処理中にリストから項目を削除するには?
-
[解決済み] Javaコレクションをフィルタリングする方法(述語に基づく)?
-
[解決済み] Javaでリストを反復処理する方法
-
[解決済み] ArrayListから繰り返される要素を削除するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Java - JTextFieldが空かどうかを確認する
-
[解決済み] Firebase クラスにシリアライズするプロパティが見つからない
-
[解決済み] プロトコルハンドラの初期化に失敗しました。
-
[解決済み] javacが「using unchecked or unsafe operations」という警告を出す原因は何ですか?
-
[解決済み] double 型を Int 型に変換、切り捨て
-
[解決済み] Javaでのスキャナが動作しない
-
[解決済み] javax.naming.NameNotFoundException
-
[解決済み] 文字列が一意な文字であるかどうかを判定する
-
[解決済み] Maven: assembly-pluginが全く実行されない
-
[解決済み] Javaでdoubleをfloatに変換する