Java Stream APIのDistinctBy

Java Stream APIのDistinctBy

1. 概要

リスト内のさまざまな要素を検索することは、プログラマーが通常直面する一般的なタスクの1つです。 Streamsを含むJava 8以降、機能的アプローチを使用してデータを処理するための新しいAPIがあります。

この記事では、リスト内のオブジェクトの特定の属性を使用してコレクションをフィルタリングするためのさまざまな代替方法を示します。

2. ストリームAPIを使用する

Stream APIは、Objectクラスのequals()メソッドに基づいてリストのさまざまな要素を返すdistinct()メソッドを提供します。

ただし、特定の属性でフィルタリングする場合は柔軟性が低下します。 代替手段の1つは、状態を維持するフィルターを作成することです。

2.1. ステートフルフィルターの使用

考えられる解決策の1つは、ステートフルPredicate:を実装することです。

public static  Predicate distinctByKey(
    Function keyExtractor) {

    Map seen = new ConcurrentHashMap<>();
    return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}

それをテストするために、属性ageemail、およびname:を持つ次のPersonクラスを使用します

public class Person {
    private int age;
    private String name;
    private String email;
    // standard getters and setters
}

また、nameでフィルタリングされた新しいコレクションを取得するには、次を使用できます。

List personListFiltered = personList.stream()
  .filter(distinctByKey(p -> p.getName()))
  .collect(Collectors.toList());

3. Eclipseコレクションの使用

Eclipse Collectionsは、JavaでStreamsとコレクションを処理するための追加のメソッドを提供するライブラリです。

3.1. ListIterate.distinct()の使用

ListIterate.distinct()メソッドを使用すると、さまざまなHashingStrategies.を使用してStreamをフィルタリングできます。これらの戦略は、ラムダ式またはメソッド参照を使用して定義できます。

Person’sの名前でフィルタリングする場合:

List personListFiltered = ListIterate
  .distinct(personList, HashingStrategies.fromFunction(Person::getName));

または、使用する属性がプリミティブ(int、long、double)の場合、次のような特殊な関数を使用できます。

List personListFiltered = ListIterate.distinct(
  personList, HashingStrategies.fromIntFunction(Person::getAge));

3.2. メーベン依存

プロジェクトでEclipseコレクションを使用するには、pom.xmlに次の依存関係を追加する必要があります。


    org.eclipse.collections
    eclipse-collections
    8.2.0

Eclipseコレクションライブラリの最新バージョンは、Maven Centralリポジトリにあります。

このライブラリの詳細については、this articleにアクセスしてください。

4. Using Vavr (Javaslang *)*

これは、不変のデータと機能制御構造を提供するJava 8の機能ライブラリです。

4.1. List.distinctByの使用

リストをフィルタリングするために、このクラスは、含まれているオブジェクトの属性でフィルタリングできるdistinctBy()メソッドを持つ独自のListクラスを提供します。

List personListFiltered = List.ofAll(personList)
  .distinctBy(Person::getName)
  .toJavaList();

4.2. メーベン依存

プロジェクトでVavrを使用するために、次の依存関係をpom.xmlに追加します。


    io.vavr
    vavr
    0.9.0

Vavrライブラリの最新バージョンはMaven Centralリポジトリにあります。

このライブラリの詳細については、this articleにアクセスしてください。

5. StreamExの使用

このライブラリは、Java 8ストリーム処理に役立つクラスとメソッドを提供します。

5.1. StreamEx.distinctの使用

提供されるクラス内にはStreamExがあり、これにはdistinctメソッドがあり、区別したい属性への参照を送信できます。

List personListFiltered = StreamEx.of(personList)
  .distinct(Person::getName)
  .toList();

5.2. メーベン依存

プロジェクトでStreamExを使用するために、次の依存関係をpom.xmlに追加します。


    one.util
    streamex
    0.6.5

StreamExライブラリの最新バージョンは、Maven Centralリポジトリにあります。

6. 結論

このクイックチュートリアルでは、標準のJava 8 APIと他のライブラリの追加の選択肢を使用した属性に基づいて、ストリームのさまざまな要素を取得する方法の例を検討しました。

いつものように、完全なコードはover on GitHubで利用できます。