Stream Col­lectors är en kraftfull funktion i Java 8 Stream API som gör det möjligt att samla in och bearbeta data på ett effektivt sätt. Här förklarar vi deras struktur och hur Java-metoden collect() kan användas.

Hur kan Java collect() användas?

En ström­kol­lek­tor kan användas för att skapa en lista, upp­sätt­ning eller karta från en ström. En ström är en sekvens av element som bearbetas efter varandra. Kol­lek­tor­gräns­snit­tet till­han­da­hål­ler en upp­sätt­ning re­duk­tions­o­pe­ra­tio­ner för data i en ström­rör­led­ning. Dessa är ter­mi­na­lo­pe­ra­tio­ner som samlar in och sam­man­fo­gar re­sul­ta­ten från mel­lan­lig­gan­de steg.

Col­lectors kan användas för att filtrera eller sortera objekt från en ström. Ag­gre­ge­ring är också möjligt, till exempel att summera siffror, kombinera strängar eller räkna element. Dessutom har Col­lectors funk­tio­ner som kan omvandla in­ne­hål­let i en ström till en specifik struktur. Du kan till exempel omvandla en lista till en karta. Grup­pe­ring­ar hjälper till att ka­te­go­ri­se­ra element med vissa egen­ska­per eller villkor. Viktigast av allt är att ström­kol­lek­to­rer har fördelen att de kan bearbeta data samtidigt med hjälp av flera trådar. Detta gör att ope­ra­tio­ner kan utföras mycket snabbare och ef­fek­ti­va­re, särskilt med stora da­ta­mäng­der.

Vad är syntaxen för Java collect()?

Metoden ac­cep­te­rar en Collector som beskriver hur elementen i strömmen ska samlas in och ag­gre­ge­ras som ett argument. En Collector är ett gräns­snitt som till­han­da­hål­ler olika metoder för att aggregera strö­me­le­ment till en specifik form, till exempel till en lista, en upp­sätt­ning eller en karta.

Det finns två varianter av Java Stream-metoden collect():

  1. <R> R collect(Supplier<R> le­ve­ran­tör, Bi­Con­su­mer<R, ? super T> ac­ku­mu­la­tor,Bi­Con­su­mer<R, R> kom­bi­ne­ra­re)
  2. <R, A> R collect(Collector<? super T, A, R> collector)

Den första varianten har tre funk­tio­ner som argument:

  • le­ve­ran­tör: skapar en behållare som kommer att användas för mel­lan­re­sul­tat
  • ac­ku­mu­la­tor: beräknar det slutliga re­sul­ta­tet
  • kom­bi­na­tor: kom­bi­ne­rar re­sul­ta­ten från pa­ral­lel­la strö­mo­pe­ra­tio­ner

Dessa för­de­fi­ni­e­ra­de samlare ingår redan i stan­dard­bib­li­o­te­ket och kan enkelt im­por­te­ras och användas.

Den andra varianten ac­cep­te­rar en Collector som argument och re­tur­ne­rar ett resultat.

  • R: typ av resultat
  • T: typen av element i strömmen
  • A: typen av ac­ku­mu­la­tor som lagrar det mel­lan­lig­gan­de till­stån­det för samlarens operation
  • samlare: utför re­duk­tions­o­pe­ra­tio­nen.

Genom att använda denna variant kan ut­veck­la­re skapa anpassade Col­lectors som är specifikt skräd­dar­syd­da efter deras behov och ger större flex­i­bi­li­tet och kontroll över re­duk­tions­pro­ces­sen.

Vilka är praktiska exempel på an­vänd­ning av Java collect()?

Nedan il­lu­stre­rar vi olika funk­tio­ner i metoden Stream.collect(). Du bör redan vara bekant med de grund­läg­gan­de Java-ope­ra­to­rer­na innan du går vidare till sam­lings­ram­ver­ket.

Sam­man­fo­ga en lista med strängar

Med Java Collect() kan vi sam­man­fo­ga en lista med strängar för att få en ny sträng:

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

Re­sul­ta­tet är:

abcde
a, b, c, d, e
Java

I den första be­räk­ning­en användes endast en StringBuil­der-instans och det fanns ingen kom­bi­na­tor­funk­tion. Det är därför re­sul­ta­tet blev abcde.

I den andra utdata sam­man­slog kom­bi­na­tor­funk­tio­nen StringBuil­der-in­stan­ser­na och se­pa­re­ra­de dem med ett kom­ma­tec­ken.

Samla element i en lista med toList()

Vi kan använda funk­tio­nen filter() för att välja ut vissa element i en lista och sedan använda toList() för att lagra dem i en ny lista.

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 nya listan finns endast udda tal:

[1, 3, 5, 7]
Java

Samla element i en upp­sätt­ning med toSet()

På samma sätt kan vi välja element och skapa en ny upp­sätt­ning av dem. Elementen i en upp­sätt­ning behöver inte ordnas i någon specifik ordning.

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

Detta visar re­sul­ta­tet:

[2, 4, 6]
Java

Samla element i en karta med toMap()

En karta kan användas till­sam­mans med Java collect() för att tilldela ett värde till varje nyckel.

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 utdata kan vi se att varje jämnt tal i indata har till­de­lats ett värde som är identiskt med det:

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

Kombinera element i en sträng med joining()

Metoden joining() kom­bi­ne­rar element i en ström i den ordning de visas och använder en separator för att separera elementen. Se­pa­ra­torn skickas som ett argument till joining(). Om ingen separator anges använder joining() den tomma strängen "".

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­ten är:

result1 ==> "abc"
result2 ==> "{a,b,c}"
Java
Gå till huvudmeny