DistinctBy in der Java Stream API

DistinctBy in der Java Stream API

1. Überblick

Die Suche nach verschiedenen Elementen in einer Liste ist eine der häufigsten Aufgaben, mit denen wir als Programmierer normalerweise konfrontiert sind. Ab Java 8 haben wir unter Einbeziehung vonStreams eine neue API zur Verarbeitung von Daten mithilfe eines funktionalen Ansatzes.

In diesem Artikel werden verschiedene Alternativen zum Filtern einer Sammlung anhand eines bestimmten Attributs von Objekten in der Liste gezeigt.

2. Verwenden der Stream-API

Die Stream-API stellt die Methodedistinct()bereit, die verschiedene Elemente einer Liste basierend auf der Methodeequals()der KlasseObjectzurückgibt.

Es wird jedoch weniger flexibel, wenn wir nach einem bestimmten Attribut filtern möchten. Eine der Alternativen besteht darin, einen Filter zu schreiben, der den Zustand beibehält.

2.1. Verwenden eines Stateful-Filters

Eine der möglichen Lösungen wäre die Implementierung eines StatefulPredicate:

public static  Predicate distinctByKey(
    Function keyExtractor) {

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

Zum Testen verwenden wir die folgende KlassePerson mit den Attributenage,email undname:

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

Und um eine neue gefilterte Sammlung nachname zu erhalten, können wir Folgendes verwenden:

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

3. Verwenden von Eclipse-Sammlungen

Eclipse Collections ist eine Bibliothek, die zusätzliche Methoden zur Verarbeitung vonStreams und Sammlungen in Java bereitstellt.

3.1. Verwenden SieListIterate.distinct()

Mit der MethodeListIterate.distinct() können wirStream mit verschiedenenHashingStrategies. filtern. Diese Strategien können mithilfe von Lambda-Ausdrücken oder Methodenreferenzen definiert werden.

Wenn wir nach dem Namen vonPerson’sfiltern möchten:

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

Wenn das Attribut, das wir verwenden möchten, primitiv ist (int, long, double), können wir eine spezielle Funktion wie die folgende verwenden:

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

3.2. Maven-Abhängigkeit

Wir müssen unserenpom.xml die folgenden Abhängigkeiten hinzufügen, um Eclipse-Sammlungen in unserem Projekt verwenden zu können:


    org.eclipse.collections
    eclipse-collections
    8.2.0

Die neueste Version der Eclipse Collections-Bibliothek finden Sie im Repository vonMaven Central.

Um mehr über diese Bibliothek zu erfahren, gehen Sie zuthis article.

4. Using Vavr (Javaslang *) *

Dies ist eine Funktionsbibliothek für Java 8, die unveränderliche Daten und Funktionskontrollstrukturen bereitstellt.

4.1. Verwenden vonList.distinctBy

Zum Filtern von Listen stellt diese Klasse eine eigene List-Klasse bereit, die über die MethodedistinctBy()verfügt, mit der wir nach Attributen der darin enthaltenen Objekte filtern können:

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

4.2. Maven-Abhängigkeit

Wir werden die folgenden Abhängigkeiten zu unserenpom.xmlhinzufügen, um Vavr in unserem Projekt zu verwenden.


    io.vavr
    vavr
    0.9.0

Sie finden die neueste Version der Vavr-Bibliothek im Repository vonMaven Central.

Um mehr über diese Bibliothek zu erfahren, gehen Sie zuthis article.

5. Verwenden von StreamEx

Diese Bibliothek bietet nützliche Klassen und Methoden für die Verarbeitung von Java 8-Streams.

5.1. Verwenden vonStreamEx.distinct

Innerhalb der bereitgestellten Klassen befindet sichStreamEx mit der Methodedistinct, an die wir einen Verweis auf das Attribut senden können, bei dem wir unterscheiden möchten:

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

5.2. Maven-Abhängigkeit

Wir werden die folgenden Abhängigkeiten zu unserenpom.xmlhinzufügen, um StreamEx in unserem Projekt zu verwenden.


    one.util
    streamex
    0.6.5

Sie finden die neueste Version der StreamEx-Bibliothek im Repository vonMaven Central.

6. Fazit

In diesem kurzen Lernprogramm haben wir Beispiele untersucht, wie verschiedene Elemente eines Streams basierend auf einem Attribut unter Verwendung der Standard-Java 8-API und zusätzlichen Alternativen mit anderen Bibliotheken abgerufen werden können.

Wie immer ist der vollständige Codeover on GitHub verfügbar.