Javaコレクションから要素を削除する

Javaコレクションから要素を削除する

1. 概要

このクイックチュートリアルでは、we’re going to talk about four different ways to remove items from Java Collections that match certain predicates.

当然、いくつかの注意点も見ていきます。

2. コレクションの定義

まず、元のデータ構造を変更する2つのアプローチを説明します。 次に、アイテムを削除する代わりに、アイテムなしで元のCollectionのコピーを作成する他の2つのオプションについて説明します。

例全体で次のコレクションを使用して、さまざまな方法を使用して同じ結果を達成する方法を示しましょう。

Collection names = new ArrayList<>();
names.add("John");
names.add("Ana");
names.add("Mary");
names.add("Anthony");
names.add("Mark");

3. Iteratorを含む要素の削除

JavaのIteratorを使用すると、Collection内のすべての個々の要素をウォークおよび削除できます。

そのためには、まず、iteratorメソッドを使用して要素のイテレータを取得する必要があります。 その後、nextを使用して各要素にアクセスし、removeを使用してそれらを削除できます。

Iterator i = names.iterator();

while(i.hasNext()) {
    String e = i.next();
    if (e.startsWith("A")) {
        i.remove();
    }
}

その単純さにもかかわらず、考慮すべきいくつかの注意事項があります。

  • コレクションによっては、ConcurrentModificationExceptionの例外が発生する場合があります

  • 削除する前に要素を反復処理する必要があります

  • Depending on the collection, remove may behave differently than expected. 例:ArrayList.Iteratorはコレクションから要素を削除し、後続のデータを左にシフトしますが、LinkedList.Iteratorは単に次の要素へのポインタを調整します。 そのため、アイテムを削除する場合、LinkedList.IteratorArrayList.Iteratorよりもはるかに優れたパフォーマンスを発揮します

4. Java 8およびCollection.removeIf()

Java 8は、the Collection interface that provides a more concise way to remove elements using Predicate:に新しいメソッドを導入しました

names.removeIf(e -> e.startsWith("A"));

Iteratorのアプローチとは異なり、removeIfLinkedListArrayListの両方で同様に良好に機能することに注意することが重要です。

Java 8では、ArrayListはデフォルトの実装(Iteratorに依存)をオーバーライドし、別の戦略を実装します。最初に、要素を反復処理し、後でPredicate;に一致する要素にマークを付けます。 2回目の反復で、最初の反復でマークされた要素を削除(およびシフト)します。

5. Java 8とStreamの導入

Java 8の新しい主要機能の1つは、Stream(およびCollectors)の追加でした。 ソースからStreamを作成する方法はたくさんあります。 ただし、Streamインスタンスに影響を与えるほとんどの操作はそのソースを変更しません。むしろ、APIはソースのコピーを作成し、それらで必要になる可能性のある操作を実行することに重点を置いています。

StreamCollectorsを使用して、Predicateに一致する要素と一致しない要素を検索/フィルタリングする方法を見てみましょう。

5.1. Streamを含む要素の削除

filtering elements using Stream is quite straightforwardを削除する、つまり、Collectionを使用してStreamのインスタンスを作成し、Predicateを使用してfilterを呼び出し、次にcollectを呼び出す必要があります。 )sCollectors:を使用した結果

Collection filteredCollection = names
  .stream()
  .filter(e -> !e.startsWith("A"))
  .collect(Collectors.toList());

Streamingは、以前のアプローチよりも侵襲性が低く、分離を促進し、同じソースから複数のコピーを作成できるようにします。 ただし、アプリケーションで使用されるメモリも増加することに注意してください。

5.2. Collectors.partitioningBy

Stream.filterCollectorsの両方を組み合わせると非常に便利ですが、we may run into scenarios where we need both matching and non-matching elements.はそのような場合、Collectors.partitioningByを利用できます。

Map> classifiedElements = names
    .stream()
    .collect(Collectors.partitioningBy((String e) ->
      !e.startsWith("A")));

String matching = String.join(",",
  classifiedElements.get(true));
String nonMatching = String.join(",",
  classifiedElements.get(false));

このメソッドは、2つのキーtruefalseのみを含むMapを返します。各キーは、一致する要素と一致しない要素をそれぞれ含むリストを指します。

6. 結論

この記事では、Collectionsから要素を削除するいくつかの方法といくつかの警告について説明しました。

この記事のover on GitHubの完全なソースコードとすべてのコードスニペットを見つけることができます。