Stream Col­lectors er en kraftfuld funktion i Java 8 Stream API, der giver dig mulighed for at indsamle og behandle data effektivt. Her forklarer vi deres struktur og hvordan Java collect()-metoden kan bruges.

Hvordan kan Java collect() bruges?

En Stream Collector kan bruges til at oprette en liste, et sæt eller et kort fra en strøm. En strøm er en sekvens af elementer, der behandles efter hinanden. Collector-græn­se­fla­den in­de­hol­der et sæt re­duk­tions­o­pe­ra­tio­ner til data i en strøm­pipe­li­ne. Dette er terminale ope­ra­tio­ner, der samler og fletter re­sul­ta­ter­ne af mel­lem­lig­gen­de trin.

Col­lectors kan bruges til at filtrere eller sortere objekter fra en strøm. Ag­gre­ge­ring er også mulig, f.eks. at summere tal, kombinere strenge eller tælle elementer. Derudover har Col­lectors funk­tio­ner, der kan omdanne indholdet af en strøm til en bestemt struktur. Du kan f.eks. omdanne en liste til et kort. Grup­pe­rin­ger hjælper med at ka­te­go­ri­se­re elementer med bestemte egen­ska­ber eller be­tin­gel­ser. Vigtigst af alt har stream-samlere den fordel, at de kan behandle data på samme tid ved hjælp af flere tråde. Dette gør det muligt at udføre ope­ra­tio­ner meget hurtigere og mere effektivt, især med store da­ta­mæng­der.

Hvad er syntaksen for Java collect()?

Metoden ac­cep­te­rer en Collector, der beskriver, hvordan ele­men­ter­ne i strømmen skal indsamles og ag­gre­ge­res, som et argument. En Collector er en græn­se­fla­de, der tilbyder for­skel­li­ge metoder til at aggregere strø­m­e­le­men­ter i en bestemt form, for eksempel i en liste, et sæt eller et kort.

Der findes to varianter af Java Stream-metoden collect():

  1. R collect(Supplier<R> le­ve­ran­dør, Bi­Consu­mer<R, ? super T> ak­ku­mu­la­tor,Bi­Consu­mer<R, R> kombiner)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

Den første variant har tre funk­tio­ner som ar­gu­men­ter:

  • le­ve­ran­dør: opretter en container, der vil blive brugt til mel­lem­re­sul­ta­ter
  • ak­ku­mu­la­tor: beregner det endelige resultat
  • kom­bi­na­tor: kom­bi­ne­rer re­sul­ta­ter­ne af pa­ral­lel­le strømo­pe­ra­tio­ner

Disse for­ud­de­fi­ne­re­de Col­lectors er allerede in­klu­de­ret i stan­dard­bi­bli­o­te­ket og kan nemt im­por­te­res og bruges.

Den anden variant ac­cep­te­rer en Collector som argument og re­tur­ne­rer et resultat.

  • R: typen af resultat
  • T: typen af elementer i strømmen
  • A: typen af ak­ku­mu­la­tor, der gemmer den mel­lem­lig­gen­de tilstand af collector-ope­ra­tio­nen
  • collector: udfører re­duk­tions­o­pe­ra­tio­nen.

Ved at bruge denne variant kan udviklere oprette til­pas­se­de Col­lectors, der er skræd­der­sy­et til deres behov og giver større flek­si­bi­li­tet og kontrol over re­duk­tions­pro­ces­sen.

Hvad er nogle praktiske eksempler på brug af Java collect()?

Nedenfor il­lu­stre­rer vi for­skel­li­ge funk­tio­ner i Stream.collect() oden. Du bør allerede være fortrolig med de grund­læg­gen­de Java-ope­ra­to­rer, inden du går i gang med sam­lings­ram­men.

Sammenkæd en liste med strenge

Med Java Collect() kan vi sam­men­kæ­de en liste med strenge for at få en ny streng:

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

Outputtet er:

abcde
a, b, c, d, e
Java

I den første beregning blev der kun brugt én String­Bu­il­der-instans, og der var ingen kom­bi­na­tions­funk­tion. Derfor er re­sul­ta­tet abcde.

I det andet output flettede kom­bi­na­tor­funk­tio­nen String­Bu­il­der-in­stan­ser­ne sammen og adskilte dem med et komma.

Saml elementer i en liste med toList()

Vi kan bruge funk­tio­nen filter() til at vælge bestemte elementer i en liste og derefter bruge toList() til at gemme dem i en ny liste.

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

I den nye liste er der kun ulige tal:

[1, 3, 5, 7]
Java

Saml elementer i et sæt med toSet()

På samme måde kan vi vælge elementer og oprette et nyt sæt ud fra dem. Ele­men­ter­ne i et sæt behøver ikke at være ar­ran­ge­ret i en bestemt ræk­ke­føl­ge.

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

Dette viser re­sul­ta­tet:

[2, 4, 6]
Java

Saml elementer i et kort med toMap()

Et kort kan bruges sammen med Java collect() til at tildele en værdi til hver nøgle.

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

I outputtet kan vi se, at hvert lige tal i inputtet har fået tildelt en værdi, der er identisk med det:

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

Kombiner elementer i en streng med joining()

Metoden joining() kom­bi­ne­rer elementer i en strøm i den ræk­ke­føl­ge, de vises, og bruger en separator til at adskille ele­men­ter­ne. Se­pa­ra­to­ren overføres som et argument til joining(). Hvis der ikke er angivet nogen separator, bruger joining() den tomme streng "".

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

Re­sul­ta­ter­ne er:

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

2031f050ecb6acd05c8d5a15242b684b

Gå til ho­ved­me­nu­en