Java Collect(): So nutzen Sie Reduktionsoperationen
Stream Collectors sind ein leistungsstarkes Feature der Java 8 Stream API, mit dem Sie Daten effizient sammeln und verarbeiten können. Wir erklären Ihnen den Aufbau und die Einsatzmöglichkeiten der Java-Collect-Methode.
Was sind die Anwendungsbereiche für Java Collect()?
Ein Stream Collector kann verwendet werden, um eine Liste, ein Set oder eine Map aus einem Stream zu erstellen. Ein Stream ist eine Sequenz von Elementen, die nacheinander verarbeitet werden. Die Collector-Schnittstelle bietet eine Reihe von Reduktionsoperationen für Daten in einer Stream-Pipeline. Es handelt sich hierbei um Terminaloperationen, die die Ergebnisse von Zwischenschritten sammeln und zusammenführen.
Collectors können beispielsweise genutzt werden, um Objekte aus einem Stream zu filtern oder zu sortieren. Auch Aggregation ist möglich, etwa das Summieren von Zahlen, Zusammenfassen von Strings oder Zählen von Elementen. Des Weiteren besitzen Collectors Funktionen, um die Inhalte eines Streams in eine bestimmte Struktur zu transformieren. So können Sie beispielsweise eine Liste in eine Map umwandeln. Gruppierungen helfen, Elemente mit bestimmten Eigenschaften oder Bedingungen zu kategorisieren. Vor allem aber haben Stream Collectors den Vorteil, dass sie Daten mithilfe mehrerer Threads parallel verarbeiten. Dadurch können Operationen, insbesondere bei großen Datenmengen, deutlich schneller und effizienter durchgeführt werden.
Das ist die Syntax von Java Collect()
Die Methode akzeptiert einen Collector als Argument, der beschreibt, wie die Elemente des Streams gesammelt und aggregiert werden sollen. Ein Collector ist ein Interface, das verschiedene Methoden bereitstellt, um die Elemente des Streams in eine bestimmte Form zusammenzuführen – z. B. in eine Liste, ein Set oder eine Map.
Es gibt zwei Arten der Java-Collect-Methode:
- <R> R collect(Supplier<R> supplier, BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)
- <R, A> R collect(Collector<? super T, A, R> collector)
Die erste Variante hat als Argument drei Funktionen:
- supplier: Erstellt einen Container, der für die Zwischenergebnisse verwendet wird.
- accumulator: Berechnet das Endergebnis.
- combiner: Kombiniert die Ergebnisse von parallelen Stream-Operationen.
Diese vordefinierten Collectors sind bereits in der Standardbibliothek enthalten und können einfach importiert und verwendet werden.
Die zweite Variante nimmt als Argument einen Collector und gibt das Ergebnis zurück.
- R: der Typ des Ergebnisses
- T: der Typ der Elemente im Stream
- A: der Typ des Accumulators, der den Zwischenzustand der Collector-Operation speichert
- collector: Führt die Reduktionsoperation aus.
Durch die Verwendung dieser Variante können Entwickler und Entwicklerinnen maßgeschneiderte Collectors erstellen, die speziell auf ihre Anforderungen zugeschnitten sind und eine höhere Flexibilität und Kontrolle über den Reduktionsprozess bieten.
Praktische Beispiele für den Einsatz von Java Collect()
Im Folgenden illustrieren wir verschiedene Funktionen der Stream.collect()
-Methode. Sie sollten bereits mit den grundlegenden Java-Operatoren vertraut sein, bevor Sie in das Collection Framework einsteigen.
Eine Liste von Strings verketten
Mit Java Collect() können wir eine Liste von Strings konkatenieren, um einen neuen String zu erhalten:
List<String> letters = List.of("a", "b", "c", "d", "e");
// without combiner function
StringBuilder result = letters.stream().collect(StringBuilder::new, (x, y) -> x.append(y),
(a, b) -> a.append(",").append(b));
System.out.println(result.toString());
// with combiner function
StringBuilder result1 = letters.parallelStream().collect(StringBuilder::new, (x, y) -> x.append(y),
(a, b) -> a.append(",").append(b));
System.out.println(result1.toString());
JavaWir erhalten die Ausgabe:
abcde
a, b, c, d, e
JavaBei der ersten Berechnung liegt nur eine StringBuilder-Instanz vor und es wurde keine Combiner-Funktion verwendet. Deshalb lautet das Ergebnis abcde
.
Im zweiten Output erkennen wir, dass die Combiner-Funktion die StringBuilder-Instanzen zusammengeführt und sie mit einem Komma getrennt hat.
Elemente mit toList() in einer Liste sammeln
Wir können mit der Funktion filter()
bestimmte Elemente einer Liste selektieren und sie in einer neuen Liste mit toList()
speichern.
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
List<Integer> oddNumbers = numbers.stream().filter(x -> x % 2 != 0).collect(Collectors.toList());
System.out.println(oddNumbers);
JavaDie neue Liste enthält nun ausschließlich ungerade Zahlen:
[1, 3, 5, 7]
JavaElemente mit toSet() in einem Set sammeln
Analog können wir aus ausgewählten Elementen ein neues Set erstellen. Die Reihenfolge darf in einem Set ungeordnet sein.
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Set<Integer> evenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0).collect(Collectors.toSet());
System.out.println(evenNumbers);
JavaDies führt zur Ausgabe:
[2, 4, 6]
JavaElemente mit toMap() in einer Map sammeln
Eine Map in Verbindung mit Java Collect() ordnet jedem Schlüssel einen Wert zu.
List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7);
Map<Integer, String> mapEvenNumbers = numbers.parallelStream().filter(x -> x % 2 == 0)
.collect(Collectors.toMap(Function.identity(), x -> String.valueOf(x)));
System.out.println(mapEvenNumbers);
JavaIn der Ausgabe sehen wir, dass der Input, der aus geraden Zahlen besteht, seinen identischen Werten zugeordnet wurde:
{2=2, 4=4, 6=6}
JavaElemente mit joining() in einer Zeichenkette kombinieren
Die joining()
-Methode fügt jedes Element im Stream in der Reihenfolge hinzu, in der sie vorkommen und verwendet ein Trennzeichen, um die Elemente zu trennen. Das Trennzeichen wird als Argument an joining()
übergeben. Wenn kein Trennzeichen angegeben wird, benutzt joining()
den leeren String ""
.
jshell> String result1 = Stream.of("a", "b", "c").collect(Collectors.joining());
jshell> String result2 = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
JavaDie Ergebnisse lauten:
result1 ==> "abc"
result2 ==> "{a,b,c}"
Java