Guide til Java 8-gruppering av Collector

1. Introduksjon

I denne veiledningen, vi får se hvordan gruppering av samler fungerer ved hjelp av forskjellige eksempler.

For at vi skal forstå materialet som dekkes i denne opplæringen, trenger vi grunnleggende kunnskap om Java 8-funksjoner. Vi kan se på introduksjonen til Java 8 Streams og guiden til Java 8s Collectors for disse grunnleggende.

2. gruppering av Samlere

Java 8 Strøm API lar oss behandle datainnsamlinger på en deklarativ måte.

De statiske fabrikkmetodene Collectors.groupingBy () og Collectors.groupingByConcurrent () gi oss funksjonalitet som ligner påGRUPPE AV' klausul i SQL-språket. Vi bruker dem til å gruppere objekter etter noen eiendommer og lagre resultater i en Kart forekomst.

De overbelastede metodene for gruppering av er:

  • Først med en klassifiseringsfunksjon som metodeparameter:

statisk samler<>> groupingBy (Funksjonsklassifisering)
  • For det andre, med en klassifiseringsfunksjon og en andre samler som metodeparametere:

statisk samler groupingBy (Funksjonsklassifikator, Collector nedstrøms)
  • Til slutt, med en klassifiseringsfunksjon, en leverandørmetode (som gir Kart implementering som inneholder sluttresultatet), og en andre samler som metodeparametere:

statisk  Collector groupingBy (Funksjonsklassifikator, leverandør mapFactory, Collector downstream)

2.1. Eksempel på kodeoppsett

For å demonstrere bruken av gruppering av (), la oss definere en Blogg innlegg klasse (vi vil bruke en strøm av Blogg innlegg gjenstander):

klasse BlogPost {Stringtittel; Stringforfatter; BlogPostType type; int liker; } 

Neste, den BlogPostType:

enum BlogPostType {NYHETER, ANMELDELSE, GUIDE} 

Og så Liste av Blogg innlegg gjenstander:

Listeinnlegg = Arrays.asList (...);

La oss også definere en Tuple klasse som skal brukes til å gruppere innlegg etter kombinasjonen av deres type og forfatter attributter:

klasse Tuple {BlogPostType type; Stringforfatter; } 

2.2. Enkel gruppering etter en enkelt kolonne

La oss starte med det enkleste gruppering av metode, som bare tar en klassifiseringsfunksjon som parameter. En klassifiseringsfunksjon brukes på hvert element i strømmen. Vi bruker verdien som returneres av funksjonen som en nøkkel til kartet vi får fra gruppering av samler.

Å gruppere blogginnleggene i blogginnleggslisten etter deres type:

Kart postsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType)); 

2.3. gruppering av med et kompleks Kart Nøkkeltype

Klassifiseringsfunksjonen er ikke begrenset til å returnere bare en skalar- eller strengverdi. Nøkkelen til det resulterende kartet kan være et hvilket som helst objekt så lenge vi sørger for at vi implementerer det nødvendige er lik og hashcode metoder.

Å gruppere blogginnleggene i listen etter type og forfatter kombinert i en Tuple forekomst:

Kart postsPerTypeAndAuthor = posts.stream () .collect (groupingBy (post -> new Tuple (post.getType (), post.getAuthor ()))); 

2.4. Endring av returnerte Kart Verditype

Den andre overbelastningen av gruppering av tar en ekstra andre samler (nedstrøms samler) som brukes på resultatene til den første samleren.

Når vi spesifiserer en klassifiseringsfunksjon, men ikke en nedstrøms samler, blir å liste opp() samler brukes bak kulissene.

La oss bruke å sette() samler som nedstrøms samler og få en Sett av blogginnlegg (i stedet for en Liste):

Kart postsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, toSet ())); 

2.5. Gruppering etter flere felt

En annen anvendelse av nedstrøms samleren er å gjøre en sekundær gruppering av til resultatene fra den første gruppen innen.

Å gruppere Liste av Blogg innleggs først av forfatter og deretter av type:

Kart map = posts.stream () .collect (groupingBy (BlogPost :: getAuthor, groupingBy (BlogPost :: getType)));

2.6. Få gjennomsnittet fra grupperte resultater

Ved å bruke nedstrøms samler kan vi bruke aggregeringsfunksjoner i resultatene av klassifiseringsfunksjonen.

For eksempel for å finne gjennomsnittlig antall liker for hvert blogginnlegg type:

Kart gjennomsnittLikesPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, averagingInt (BlogPost :: getLikes))); 

2.7. Få summen av grupperte resultater

For å beregne totalsummen av liker for hver type:

Map likesPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, summingInt (BlogPost :: getLikes))); 

2.8. Få maksimalt eller minimum fra grupperte resultater

En annen samling vi kan utføre er å få blogginnlegget med maksimalt antall likes:

Kart maxLikesPerPostType = posts.stream () .collect (groupingBy (BlogPost :: getType, maxBy (comparingInt (BlogPost :: getLikes)))); 

På samme måte kan vi bruke minBy nedstrøms samler for å få blogginnlegget med minimum antall liker.

Merk at maxBy og minBy samlere tar hensyn til muligheten for at samlingen de brukes på kan være tom. Dette er grunnen til at verditypen i kartet er Valgfri.

2.9. Få et sammendrag for et attributt av grupperte resultater

De Samlere API tilbyr en oppsummerende samler som vi kan bruke i tilfeller der vi trenger å beregne antall, sum, minimum, maksimum og gjennomsnitt for et numerisk attributt samtidig.

La oss beregne et sammendrag for likesattributtet til blogginnleggene for hver forskjellige type:

Kart somStatisticsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, summarizingInt (BlogPost :: getLikes))); 

De IntSummaryStatistics objektet for hver type inneholder telle-, sum-, gjennomsnitt-, min- og maksverdiene for liker Egenskap. Ytterligere sammendragsobjekter finnes for doble og lange verdier.

2.10. Kartlegge grupperte resultater til en annen type

Vi kan oppnå mer komplekse aggregeringer ved å bruke en kartlegging nedstrøms samler til resultatene av klassifiseringsfunksjonen.

La oss få en sammenkobling av tittels av innleggene for hvert blogginnlegg type:

Kartlegg postsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, mapping (BlogPost :: getTitle, joining (",", "Post titles: [", "]")))); 

Det vi har gjort her er å kartlegge hver Blogg innlegg eksempel til sin tittel og reduser deretter strømmen av innleggstitler til en sammenkoblet String. I dette eksemplet, typen Kart verdien er også forskjellig fra standardverdien Liste type.

2.11. Endring av retur Kart Type

Når du bruker gruppering av samler, kan vi ikke gjøre antakelser om typen returnert Kart. Hvis vi vil være spesifikke for hvilken type Kart vi ønsker å komme oss fra gruppen, så kan vi bruke den tredje varianten av gruppering av metode som lar oss endre typen av Kart ved å passere en Kart leverandørfunksjon.

La oss hente en EnumMap ved å passere en EnumMap leverandørfunksjon til gruppering av metode:

EnumMap postsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, () -> new EnumMap (BlogPostType.class), toList ())); 

3. Samtidig gruppering av Samler

Lik gruppering av er den groupingByConcurrent samler, som utnytter flerkjernearkitekturer. Denne samleren har tre overbelastede metoder som tar nøyaktig de samme argumentene som de respektive overbelastede metodene til gruppering av samler. Returtypen til groupingByConcurrent samler må imidlertid være en forekomst av ConcurrentHashMap klasse eller en underklasse av den.

For å utføre en grupperingsoperasjon samtidig, må strømmen være parallell:

ConcurrentMap postsPerType = posts.parallelStream () .collect (groupingByConcurrent (BlogPost :: getType)); 

Hvis vi velger å bestå en Kart leverandørfunksjon til groupingByConcurrent samler, så må vi sørge for at funksjonen returnerer enten a ConcurrentHashMap eller en underklasse av den.

4. Java 9-tillegg

Java 9 introduserte to nye samlere som fungerer godt med gruppering av; mer informasjon om dem finner du her.

5. Konklusjon

I denne artikkelen undersøkte vi bruken av gruppering av samler tilbudt av Java 8 Samlere API.

Vi lærte hvordan gruppering av kan brukes til å klassifisere en strøm av elementer basert på en av egenskapene deres, og hvordan resultatene av denne klassifiseringen kan samles videre, muteres og reduseres til endelige beholdere.

Den komplette implementeringen av eksemplene i denne artikkelen finner du i GitHub-prosjektet.


$config[zx-auto] not found$config[zx-overlay] not found