Stream Coll­ec­tors sind ein leis­tungs­star­kes Feature der Java 8 Stream API, mit dem Sie Daten effizient sammeln und ver­ar­bei­ten können. Wir erklären Ihnen den Aufbau und die Ein­satz­mög­lich­kei­ten der Java-Collect-Methode.

Was sind die An­wen­dungs­be­rei­che 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 nach­ein­an­der ver­ar­bei­tet werden. Die Collector-Schnitt­stel­le bietet eine Reihe von Re­duk­ti­ons­ope­ra­tio­nen für Daten in einer Stream-Pipeline. Es handelt sich hierbei um Ter­mi­nal­ope­ra­tio­nen, die die Er­geb­nis­se von Zwi­schen­schrit­ten sammeln und zu­sam­men­füh­ren.

Coll­ec­tors können bei­spiels­wei­se genutzt werden, um Objekte aus einem Stream zu filtern oder zu sortieren. Auch Ag­gre­ga­ti­on ist möglich, etwa das Summieren von Zahlen, Zu­sam­men­fas­sen von Strings oder Zählen von Elementen. Des Weiteren besitzen Coll­ec­tors Funk­tio­nen, um die Inhalte eines Streams in eine bestimmte Struktur zu trans­for­mie­ren. So können Sie bei­spiels­wei­se eine Liste in eine Map umwandeln. Grup­pie­run­gen helfen, Elemente mit be­stimm­ten Ei­gen­schaf­ten oder Be­din­gun­gen zu ka­te­go­ri­sie­ren. Vor allem aber haben Stream Coll­ec­tors den Vorteil, dass sie Daten mithilfe mehrerer Threads parallel ver­ar­bei­ten. Dadurch können Ope­ra­tio­nen, ins­be­son­de­re bei großen Da­ten­men­gen, deutlich schneller und ef­fi­zi­en­ter durch­ge­führt werden.

Das ist die Syntax von Java Collect()

Die Methode ak­zep­tiert einen Collector als Argument, der be­schreibt, wie die Elemente des Streams gesammelt und agg­re­giert werden sollen. Ein Collector ist ein Interface, das ver­schie­de­ne Methoden be­reit­stellt, um die Elemente des Streams in eine bestimmte Form zu­sam­men­zu­füh­ren – z. B. in eine Liste, ein Set oder eine Map.

Es gibt zwei Arten der Java-Collect-Methode:

  1. <R> R collect(Supplier<R> supplier, BiCon­su­mer<R, ? super T> ac­cu­mu­la­tor,BiCon­su­mer<R, R> combiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

Die erste Variante hat als Argument drei Funk­tio­nen:

  • supplier: Erstellt einen Container, der für die Zwi­schen­er­geb­nis­se verwendet wird.
  • ac­cu­mu­la­tor: Berechnet das End­ergeb­nis.
  • combiner: Kom­bi­niert die Er­geb­nis­se von par­al­le­len Stream-Ope­ra­tio­nen.

Diese vor­de­fi­nier­ten Coll­ec­tors sind bereits in der Stan­dard­bi­blio­thek enthalten und können einfach im­por­tiert und verwendet werden.

Die zweite Variante nimmt als Argument einen Collector und gibt das Ergebnis zurück.

  • R: der Typ des Er­geb­nis­ses
  • T: der Typ der Elemente im Stream
  • A: der Typ des Ac­cu­mu­la­tors, der den Zwi­schen­zu­stand der Collector-Operation speichert
  • collector: Führt die Re­duk­ti­ons­ope­ra­ti­on aus.

Durch die Ver­wen­dung dieser Variante können Ent­wick­ler und Ent­wick­le­rin­nen maß­ge­schnei­der­te Coll­ec­tors erstellen, die speziell auf ihre An­for­de­run­gen zu­ge­schnit­ten sind und eine höhere Fle­xi­bi­li­tät und Kontrolle über den Re­duk­ti­ons­pro­zess bieten.

Prak­ti­sche Beispiele für den Einsatz von Java Collect()

Im Folgenden il­lus­trie­ren wir ver­schie­de­ne Funk­tio­nen der Stream.collect()-Methode. Sie sollten bereits mit den grund­le­gen­den Java-Ope­ra­to­ren vertraut sein, bevor Sie in das Coll­ec­tion Framework ein­stei­gen.

Eine Liste von Strings verketten

Mit Java Collect() können wir eine Liste von Strings kon­ka­te­nie­ren, 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());
Java

Wir erhalten die Ausgabe:

abcde
a, b, c, d, e
Java

Bei der ersten Be­rech­nung liegt nur eine String­Buil­der-Instanz vor und es wurde keine Combiner-Funktion verwendet. Deshalb lautet das Ergebnis abcde.

Im zweiten Output erkennen wir, dass die Combiner-Funktion die String­Buil­der-Instanzen zu­sam­men­ge­fü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 se­lek­tie­ren 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);
Java

Die neue Liste enthält nun aus­schließ­lich ungerade Zahlen:

[1, 3, 5, 7]
Java

Elemente mit toSet() in einem Set sammeln

Analog können wir aus aus­ge­wähl­ten Elementen ein neues Set erstellen. Die Rei­hen­fol­ge darf in einem Set un­ge­ord­net 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);
Java

Dies führt zur Ausgabe:

[2, 4, 6]
Java

Elemente mit toMap() in einer Map sammeln

Eine Map in Ver­bin­dung 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);
Java

In der Ausgabe sehen wir, dass der Input, der aus geraden Zahlen besteht, seinen iden­ti­schen Werten zu­ge­ord­net wurde:

{2=2, 4=4, 6=6}
Java

Elemente mit joining() in einer Zei­chen­ket­te kom­bi­nie­ren

Die joining()-Methode fügt jedes Element im Stream in der Rei­hen­fol­ge hinzu, in der sie vorkommen und verwendet ein Trenn­zei­chen, um die Elemente zu trennen. Das Trenn­zei­chen wird als Argument an joining() übergeben. Wenn kein Trenn­zei­chen 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(",", "{", "}"));
Java

Die Er­geb­nis­se lauten:

result1 ==> "abc"
result2 ==> "{a,b,c}"
Java
Zum Hauptmenü