Vodič za grupiranje Java 8By Collector

1. Uvod

U ovom vodiču, vidjet ćemo kako grupiranjeBy kolekcionarski radovi koristeći se raznim primjerima.

Da bismo razumjeli materijal obuhvaćen ovim uputstvom, trebat će nam osnovno znanje o značajkama Java 8. Za ove osnove možemo pogledati uvod u Java 8 Streams i vodič kroz Java 8's Collectors.

2. grupiranjeBy Kolekcionari

Java 8 Stream API nam omogućuje obradu zbirki podataka na deklarativni način.

Statičke tvorničke metode Collectors.groupingBy () i Collectors.groupingByConcurrent () pružite nam funkcionalnost sličnu "SKUPI PO ' klauzula u jeziku SQL. Koristimo ih za grupiranje objekata po nekim svojstvima i spremanje rezultata u Karta primjer.

Preopterećene metode grupiranjeBy su:

  • Prvo, s funkcijom klasifikacije kao parametrom metode:

statički kolektor<>> groupingBy (klasifikator funkcija)
  • Drugo, s funkcijom klasifikacije i drugim sakupljačem kao parametrima metode:

statički kolektor groupingBy (Klasifikator funkcija, Kolektor nizvodno)
  • Konačno, s klasifikacijskom funkcijom, metoda dobavljača (koja pruža Karta implementacija koja sadrži krajnji rezultat), a drugi kolektor kao parametre metode:

statički  Grupiranje kolektoraBy (Klasifikator funkcija, Mapa dobavljačaTvornica, Kolektor nizvodno)

2.1. Primjer postavljanja koda

Da bi se demonstrirala upotreba grupiranjeBy (), definirajmo a BlogPost klase (koristit ćemo tok BlogPost objekti):

klasa BlogPost {Naslov niza; Autor niza; Tip BlogPostType; int lajkovi; } 

Dalje, BlogPostType:

enum BlogPostType {VIJESTI, PREGLED, VODIČ} 

Onda Popis od BlogPost objekti:

Popis postova = Arrays.asList (...);

Definirajmo i a Korijen klase koja će se koristiti za grupiranje postova kombinacijom njihovih tip i Autor atributi:

klasa Tuple {vrsta tipa BlogPostType; Autor niza; } 

2.2. Jednostavno grupiranje u jedan stupac

Krenimo od najjednostavnijeg grupiranjeBy metoda koja za svoj parametar uzima samo funkciju klasifikacije. Funkcija klasifikacije primjenjuje se na svaki element toka. Vrijednost koju je funkcija vratila koristimo kao ključ karte koju dobivamo iz grupiranjeBy kolektor.

Da grupiraju postove na blogu na popisu blogova po njihovim osobama tip:

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

2.3. grupiranjeBy s Kompleksom Karta Tip ključa

Funkcija klasifikacije nije ograničena na vraćanje samo skalarne ili String vrijednosti. Ključ rezultirajuće mape mogao bi biti bilo koji objekt sve dok osiguravamo da provedemo potrebno jednako i hashcode metode.

Za grupiranje postova na blogu na popisu po tip i Autor kombinirani u a Korijen primjer:

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

2.4. Izmjena vraćenog Karta Vrsta vrijednosti

Drugo preopterećenje od grupiranjeBy uzima dodatni drugi kolektor (nizvodni kolektor) koji se primjenjuje na rezultate prvog kolektora.

Kada odredimo funkciju klasifikacije, ali ne i nizvodni kolektor, izlistati() kolektor se koristi iza kulisa.

Iskoristimo postaviti() kolektor kao nizvodni kolektor i dobiti a Postavi postova na blogu (umjesto Popis):

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

2.5. Grupiranje po više polja

Drugačija primjena nizvodnog kolektora je napraviti sekundar grupiranjeBy na rezultate prve skupine po.

Za grupiranje Popis od BlogPostprvi od Autor a zatim po tip:

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

2.6. Dobivanje prosjeka iz grupiranih rezultata

Korištenjem nizvodnog kolektora možemo primijeniti funkcije agregiranja u rezultatima funkcije klasifikacije.

Na primjer, za pronalaženje prosječnog broja sviđanja za svaki post na blogu tip:

Mapiraj prosjekLikesPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, averagingInt (BlogPost :: getLikes))); 

2.7. Dobivanje zbroja iz grupiranih rezultata

Za izračun ukupnog zbroja sviđanja za svakoga tip:

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

2.8. Dobivanje maksimuma ili minimuma iz grupiranih rezultata

Još jedna agregacija koju možemo izvesti je da dobijemo post na blogu s maksimalnim brojem sviđanja:

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

Slično tome, možemo primijeniti minBy nizvodni sakupljač kako bi dobio post na blogu s minimalnim brojem sviđanja.

Imajte na umu da maxBy i minBy sakupljači uzimaju u obzir mogućnost da zbirka na koju se primjenjuju može biti prazna. Zbog toga je vrsta vrijednosti na karti Neobvezno.

2.9. Dobivanje sažetka za atribut grupiranih rezultata

The Kolekcionari API nudi sakupljač sažetaka koji možemo koristiti u slučajevima kada moramo istodobno izračunati broj, zbroj, minimum, maksimum i prosjek numeričkog atributa.

Izračunajmo sažetak za atribut sviđanja blogovskih postova za svaku različitu vrstu:

Karta likeStatisticsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, summarizingInt (BlogPost :: getLikes))); 

The IntSummaryStatistics objekt za svaku vrstu sadrži brojanje, zbroj, prosjek, min i max vrijednosti za sviđanja atribut. Postoje dodatni sažeti objekti za dvostruke i duge vrijednosti.

2.10. Mapiranje grupiranih rezultata u drugu vrstu

Složenije agregacije možemo postići primjenom a mapiranje nizvodni kolektor do rezultata funkcije klasifikacije.

Idemo u spajanje titulas postova za svaki post na blogu tip:

Mapiraj postsPerType = posts.stream () .collect (groupingBy (BlogPost :: getType, mapping (BlogPost :: getTitle, pridruživanje (",", "Naslovi postova: [", "]"))))); 

Ono što smo ovdje učinili je mapiranje svakog BlogPost instancu na svoj titula a zatim smanjite tok naslova posta na spojene Niz. U ovom primjeru, vrsta datoteke Karta vrijednost se također razlikuje od zadane Popis tip.

2.11. Izmjena Povratka Karta Tip

Kada koristite grupiranjeBy kolekcionar, ne možemo pretpostaviti o vrsti vraćenog Karta. Ako želimo biti precizni o kojoj vrsti Karta želimo doći iz grupe do, tada možemo koristiti treću varijaciju grupiranjeBy metoda koja nam omogućuje promjenu vrste Karta prolaskom a Karta funkcija dobavljača.

Dohvatimo EnumMap prolazeći an EnumMap funkcija dobavljača za grupiranjeBy metoda:

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

3. Istovremeno grupiranjeBy Kolektor

Slično grupiranjeBy je groupingByConcurrent kolektor, koji koristi višejezgrene arhitekture. Ovaj kolektor ima tri preopterećene metode koje uzimaju potpuno iste argumente kao i odgovarajuće preopterećene metode datoteke grupiranjeBy kolektor. Tip povrata groupingByConcurrent kolektor, međutim, mora biti instanca ConcurrentHashMap razred ili njegov podrazred.

Da bi se istovremeno izvršila operacija grupiranja, tok mora biti paralelan:

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

Ako odlučimo položiti a Karta funkcija dobavljača za groupingByConcurrent collector, tada moramo biti sigurni da funkcija vraća bilo a ConcurrentHashMap ili njegov podrazred.

4. Dodaci Java 9

Java 9 predstavila je dva nova kolektora s kojima se dobro surađuje grupiranjeBy; više informacija o njima možete pronaći ovdje.

5. Zaključak

U ovom smo članku istražili upotrebu grupiranjeBy kolektor koji nudi Java 8 Kolekcionari API.

Naučili smo kako grupiranjeBy može se koristiti za klasificiranje toka elemenata na temelju jednog od njihovih atributa i kako se rezultati ove klasifikacije mogu dalje prikupljati, mutirati i svesti na konačne spremnike.

Kompletna primjena primjera u ovom članku može se naći u projektu GitHub.