Stream Collectors zijn een krachtige functie in de Java 8 Stream API waarmee u gegevens efficiënt kunt verzamelen en verwerken. Hier leggen we uit hoe ze zijn opgebouwd en hoe u de Java collect()-methode kunt gebruiken.

Hoe kan Java collect() worden gebruikt?

Een Stream Collector kan worden gebruikt om een lijst, set of map te maken op basis van een stream. Een stream is een reeks elementen die achter elkaar worden verwerkt. De Collector-interface biedt een reeks reductiebewerkingen voor gegevens in een stream-pijplijn. Dit zijn terminale bewerkingen die de resultaten van tussenstappen verzamelen en samenvoegen.

Collectors kunnen worden gebruikt om objecten uit een stream te filteren of te sorteren. Aggregatie is ook mogelijk, zoals het optellen van getallen, het combineren van strings of het tellen van elementen. Daarnaast hebben Collectors functies waarmee de inhoud van een stream kan worden omgezet in een specifieke structuur. U kunt bijvoorbeeld een lijst omzetten in een map. Groeperingen helpen bij het categoriseren van elementen met bepaalde eigenschappen of voorwaarden. Het belangrijkste voordeel van streamcollectors is dat ze gegevens tegelijkertijd met meerdere threads kunnen verwerken. Hierdoor kunnen bewerkingen veel sneller en efficiënter worden uitgevoerd, vooral bij grote hoeveelheden gegevens.

Wat is de syntaxis voor Java collect()?

De methode accepteert een Collector die beschrijft hoe de elementen van de stream moeten worden verzameld en geaggregeerd als argument. Een Collector is een interface die verschillende methoden biedt om streamelementen te aggregeren tot een specifieke vorm, bijvoorbeeld tot een lijst, een set of een map.

Er zijn twee varianten van de Java Stream collect()-methode:

  1. R collect(Supplier<R> leverancier, BiConsumer<R, ? super T> accumulator,BiConsumer<R, R> combiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

De eerste variant heeft drie functies als argumenten:

  • leverancier: maakt een container aan die gebruikt zal worden voor tussenresultaten
  • accumulator: berekent het eindresultaat
  • combiner: combineert de resultaten van parallelle streambewerkingen

Deze vooraf gedefinieerde Collectors zijn al opgenomen in de standaardbibliotheek en kunnen eenvoudig worden geïmporteerd en gebruikt.

De tweede variant accepteert een Collector als argument en retourneert een resultaat.

  • R: het type resultaat
  • T: het type elementen in de stream
  • A: het type accumulator dat de tussenliggende status van de collectorbewerking opslaat
  • collector: voert de reductiebewerking uit.

Door deze variant te gebruiken, kunnen ontwikkelaars aangepaste Collectors maken die specifiek zijn afgestemd op hun vereisten en die meer flexibiliteit en controle bieden over het reductieproces.

Wat zijn praktische voorbeelden voor het gebruik van Java collect()?

Hieronder illustreren we verschillende functies van de Stream.collect(). Je moet al bekend zijn met de basis Java-operatoren voordat je aan de slag gaat met het collectieframework.

Een lijst met strings samenvoegen

Met Java Collect() kunnen we een lijst met strings samenvoegen om een nieuwe string te krijgen:

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

De uitvoer is:

abcde
a, b, c, d, e
Java

In de eerste berekening werd slechts één StringBuilder-instantie gebruikt en was er geen combiner-functie. Daarom is het resultaat abcde.

In de tweede uitvoer heeft de combiner-functie de StringBuilder-instanties samengevoegd en ze gescheiden met een komma.

Verzamel elementen in een lijst met toList()

We kunnen de functie filter() gebruiken om bepaalde elementen van een lijst te selecteren en vervolgens toList() gebruiken om ze in een nieuwe lijst op te slaan.

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

In de nieuwe lijst staan alleen oneven getallen:

[1, 3, 5, 7]
Java

Verzamel elementen in een set met toSet()

Op dezelfde manier kunnen we elementen selecteren en daaruit een nieuwe set maken. De elementen in een set hoeven niet in een bepaalde volgorde te worden gerangschikt.

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

Dit geeft de volgende uitvoer weer:

[2, 4, 6]
Java

Verzamel elementen in een map met toMap()

Een map kan samen met Java collect() worden gebruikt om aan elke sleutel een waarde toe te wijzen.

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 de uitvoer zien we dat elk even getal in de invoer een waarde heeft gekregen die identiek is aan het getal zelf:

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

Combineer elementen in een string met joining()

De methode joining() combineert elementen in een stream in de volgorde waarin ze voorkomen en gebruikt een scheidingsteken om de elementen te scheiden. Het scheidingsteken wordt als argument doorgegeven aan joining(). Als er geen scheidingsteken is opgegeven, gebruikt joining() de lege tekenreeks "".

jshell> String result1 = Stream.of("a", "b", "c").collect(Collectors.joining());
jshell> String result2 = Stream.of("a", "b", "c").collect(Collectors.joining(",", "{", "}"));
Java

De resultaten zijn:

result1 ==> "abc"
result2 ==> "{a,b,c}"
Java
Ga naar hoofdmenu