Bevezetés a Protonpack-ba

1. Áttekintés

Ebben az oktatóanyagban megvizsgáljuk a Protonpack főbb jellemzőit, amely egy olyan könyvtár, amely kibővíti a szabványt Folyam API néhány kiegészítő funkció hozzáadásával.

A Java alapjainak felfedezéséhez olvassa el ezt az írást itt Folyam API.

2. Maven-függőség

A Protonpack könyvtár használatához hozzá kell adnunk egy függőséget pom.xml fájl:

 com.codepoetics protonpack 1.15 

Ellenőrizze a legújabb verziót a Maven Central oldalon.

3. StreamUtils

Ez a fő osztály, amely kibővíti a Java szabványát Folyam API.

Az itt tárgyalt összes módszer köztes művelet, ami azt jelenti, hogy módosítják a Folyam de nem váltja ki annak feldolgozását.

3.1. takeWhile () és takeUntil ()

takeWhile () értékeket vesz a forrásfolyamból mindaddig, amíg megfelelnek a szállított feltételnek:

Stream streamOfInt = Stream .iterate (1, i -> i + 1); Lista eredménye = StreamUtils .takeWhile (streamOfInt, i -> i <5) .collect (Collectors.toList ()); assertThat (eredmény). tartalmaz (1, 2, 3, 4);

Fordítva, takeUntil () értékeket vesz fel amíg egy érték nem teljesíti a szállított feltételt majd megáll:

Stream streamOfInt = Stream .iterate (1, i -> i + 1); Lista eredménye = StreamUtils .takeUntil (streamOfInt, i -> i> = 5) .collect (Collectors.toList ()); assertThat (eredmény) .conactExactly (1, 2, 3, 4);

Java 9-től kezdve takeWhile () a szabvány része Folyam API.

3.2. postai irányítószám()

postai irányítószám() két vagy három adatfolyamot vesz be és kombináló funkcióként. A módszer, a metódus az egyes folyamok azonos helyzetéből vesz egy értéket, és átadja azt a kombinátornak.

Addig teszi, amíg az egyik adatfolyam elfogy az értékéből:

Vonós [] klubok = {"Juventus", "Barcelona", "Liverpool", "PSG"}; Vonós [] játékosok = {"Ronaldo", "Messi", "Salah"}; Set zippedFrom2Sources = StreamUtils .zip (stream (klubok), stream (játékosok), (klub, játékos) -> club + "" + játékos) .collect (Collectors.toSet ()); assertThat (zippedFrom2Sources). tartalmaz ("Juventus Ronaldo", "Barcelona Messi", "Liverpool Salah"); 

Hasonlóképpen egy túlterhelt postai irányítószám() amely három forrásból áll:

Vonós [] ligák = {"Serie A", "La Liga", "Premier League"}; Set zippedFrom3Sources = StreamUtils .zip (stream (klubok), stream (játékosok), stream (ligák), (klub, játékos, liga) -> club + "" + játékos + "" + liga ".collect (Collectors.toSet ( )); assertThat (zippedFrom3Sources). tartalmaz ("Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League");

3.3. zipWithIndex ()

zipWithIndex () értékeket vesz fel, és minden értéket indexével tömörít, hogy indexelt értékeket hozzon létre:

Stream streamOfClubs = Stream .of ("Juventus", "Barcelona", "Liverpool"); Készlet zipsWithIndex = StreamUtils .zipWithIndex (streamOfClubs) .collect (Collectors.toSet ()); assertThat (zipsWithIndex). tartalmaz (Indexed.index (0, "Juventus"), Indexed.index (1, "Barcelona"), Indexed.index (2, "Liverpool"));

3.4. összeolvad()

összeolvad() több forrásfolyammal és kombinátorral működik. Azt minden forrásfolyamból elveszi ugyanazon indexpozíció értékét és átadja a kombinátornak.

A módszer úgy működik, hogy minden adatfolyamból 1 értéket vesz fel ugyanazon indexből egymás után, a mag érték.

Ezután az értéket továbbítják a kombinátornak, és a kapott kombinált értéket visszavezetik a kombinátorhoz a következő érték létrehozásához:

Stream streamOfClubs = Stream .of ("Juventus", "Barcelona", "Liverpool", "PSG"); Stream streamOfPlayers = Stream .of ("Ronaldo", "Messi", "Salah"); Stream streamOfLeagues = Stream .of ("Serie A", "La Liga", "Premier League"); Állítsa be az egyesített = StreamUtils.merge (() -> "", (valOne, valTwo) -> valOne + "" + valTwo, streamOfClubs, streamOfPlayers, streamOfLeagues) .collect (Collectors.toSet ()); assertThat (egyesült) .tartalmaz ("Juventus Ronaldo Serie A", "Barcelona Messi La Liga", "Liverpool Salah Premier League", "PSG");

3.5. mergeToList ()

mergeToList () több adatfolyamot vesz bemenetként. Azt egyesíti az egyes adatfolyamok azonos indexének értékét a-ba Lista:

Stream streamOfClubs = Stream .of ("Juventus", "Barcelona", "PSG"); Stream streamOfPlayers = Stream .of ("Ronaldo", "Messi"); Folyam mergedStreamOfList = StreamUtils .mergeToList (streamOfClubs, streamOfPlayers); Lista mergedListOfList = mergedStreamOfList .collect (Collectors.toList ()); assertThat (mergedListOfList.get (0)) .containsExactly ("Juventus", "Ronaldo"); assertThat (mergedListOfList.get (1)) .containsExactly ("Barcelona", "Messi"); assertThat (mergedListOfList.get (2)) .containsExactly ("PSG");

3.6. interleave ()

interleave ()létrehoz egy alternatív értéket, amelyet több folyamból vettek az a használatával választó.

A módszer egy halmazt ad, amely minden adatfolyamtól egy értéket tartalmaz választó, és a választó kiválaszt egy értéket.

Ezután a kiválasztott érték eltávolításra kerül a halmazból, és kicserélődik a következő értékre, amelyből a kiválasztott érték származik. Ez az iteráció addig folytatódik, amíg az összes forrás el nem fogy az értékéből.

A következő példa használja interleave () hogy váltakozó értékeket hozzunk létre az a-val körbefutó stratégia:

Stream streamOfClubs = Stream .of ("Juventus", "Barcelona", "Liverpool"); Stream streamOfPlayers = Stream .of ("Ronaldo", "Messi"); Stream streamOfLeagues = Stream .of ("Serie A", "La Liga"); List interleavedList = StreamUtils .interleave (Selectors.roundRobin (), streamOfClubs, streamOfPlayers, streamOfLeagues) .collect (Collectors.toList ()); assertThat (interleavedList) .hasSize (7). pontosan tartalmaz ("Juventus", "Ronaldo", "Serie A", "Barcelona", "Messi", "La Liga", "Liverpool"); 

Ne feledje, hogy a fenti kód oktató jellegű, mert a körbetartás választó a könyvtár biztosítja as Selectors.roundRobin ().

3.7. skipUntil () és skipWhile ()

skipUntil () kihagyja az értékeket amíg egy érték nem felel meg a feltételnek:

Egész [] számok = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; List skippedUntilGreaterThan5 = StreamUtils .skipUntil (adatfolyam (számok), i -> i> 5) .collect (Collectors.toList ()); assertThat (skippedUntilGreaterThan5) .conactExactly (6, 7, 8, 9, 10); 

Ellentétben, skipWhile ()kihagyja az értékeket, miközben az értékek megfelelnek a feltételnek:

Egész [] számok = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; List skippedWhileLessThanEquals5 = StreamUtils .skipWhile (adatfolyam (számok), i -> i <= 5 ||) .collect (Collectors.toList ()); assertThat (skippedWhileLessThanEquals5) .conactExlyly (6, 7, 8, 9, 10); 

Egy fontos dolog skipWhile () az, hogy folytatja a streaminget, miután megtalálta az első értéket, amely nem felel meg a feltételnek:

List skippedWhileGreaterThan5 = StreamUtils .skipWhile (adatfolyam (számok), i -> i> 5) .collect (Collectors.toList ()); assertThat (skippedWhileGreaterThan5) .conactExactly (1, 2, 3, 4, 5, 6, 7, 8, 9, 10); 

Java 9-től kezdve dropWhile() szabványban Folyam Az API ugyanazt a funkciót biztosítja, mint az skipWhile ().

3.8. kibontakozik ()

kibontakozik () potenciálisan végtelen adatfolyamot generál egy egyéni generátor alkalmazásával az alapértékre, majd az egyes generált értékekre - a folyamot vissza lehet állítani Opcionális. Üres ():

Stream kibontva = StreamUtils .unfold (2, i -> (i <100)? Opcionális. (I * i): Opcionális. Üres ()); assertThat (kibontva.collect (Collectors.toList ())) .containsExactly (2, 4, 16, 256);

3.9. ablakos()

ablakos()a forrásfolyam több részhalmazát hozza létre Lista. A módszer forrásfolyamot vesz fel, ablak mérete és kihagyja az értéket paraméterként.

A Lista hossza megegyezik ablakméret, míg skip érték meghatározza, hogy az alkészlet hol kezdődik az előző részhalmazhoz képest:

Egész [] számok = {1, 2, 3, 4, 5, 6, 7, 8}; Lista windowedWithSkip1 = StreamUtils .windowed (stream (számok), 3, 1) .collect (Collectors.toList ()); assertThat (windowedWithSkip1) .conactExactly (asList (1, 2, 3), asList (2, 3, 4), asList (3, 4, 5), asList (4, 5, 6), asList (5, 6, 7) )); 

Ezenkívül az utolsó ablak garantáltan a kívánt méretű lesz, amint azt a következő példában láthatjuk:

A windowedWithSkip2 = StreamUtils.windowed lista (stream (számok), 3, 2) .collect (Collectors.toList ()); assertThat (windowedWithSkip2) .containsExactly (asList (1, 2, 3), asList (3, 4, 5), asList (5, 6, 7)); 

3.10. összesítés ()

Van két összesítés () egészen másképpen működő módszerek.

Az első összesítés () egy adott állítmány szerint azonos értékű elemeket csoportosít:

Egész [] számok = {1, 2, 2, 3, 4, 4, 4, 5}; Lista összesítve = StreamUtils .aggregate (Tömbök.stream (számok), (int1, int2) -> int1.compareTo (int2) == 0) .collect (Collectors.toList ()); assertThat (összesítve) .conactExactly (asList (1), asList (2, 2), asList (3), asList (4, 4, 4), asList (5)); 

Az állítmány összefüggő módon fogadja az értékeket. Ezért a fentiek más eredményt adnak, ha a számot nem rendelik.

Másrészt a második összesítés () egyszerűen megszokta csoportosítson elemeket a forrásfolyamból a kívánt méretű csoportokba:

List aggregatedFixSize = StreamUtils .aggregate (stream (számok), 5) .collect (Collectors.toList ()); assertThat (aggregatedFixSize) .containExactly (asList (1, 2, 2, 3, 4), asList (4, 4, 5)); 

3.11. aggregateOnListCondition ()

aggregateOnListCondition () csoportosítja az értékeket predikátum és aktuális aktív csoport alapján. Az állítmány a jelenleg aktív csoportot a-ként kapja meg Lista és a következő érték. Ezután meg kell határoznia, hogy a csoport folytassa-e vagy új csoportot indítson-e.

A következő példa megoldja az összefüggő egész értékek csoportba csoportosításának követelményét, ahol az egyes csoportok értékeinek összege nem lehet nagyobb, mint 5:

Egész [] számok = {1, 1, 2, 3, 4, 4, 5}; Folyam összesített = StreamUtils .aggregateOnListCondition (adatfolyam (számok), (currentList, nextInt) -> currentList.stream (). mapToInt (Integer :: intValue) .sum () + nextInt <= 5); assertThat (összesítve) .containExactly (asList (1, 1, 2), asList (3), asList (4), asList (4), asList (5));

4. Streamelhető

Példája Folyam nem használható fel újra. Emiatt, Streamelhető újrafelhasználható folyamokat nyújt ugyanazokkal a módszerekkel, mint a Folyam:

Streamable s = Streamable.of ("a", "b", "c", "d"); Összegyűjtött lista1 = s.collect (Collectors.toList ()); Összegyűjtött lista2 = s.collect (Collectors.toList ()); assertThat (gyűjtött1) .hasSize (4); assertThat (összegyűjtött2) .hasSize (4);

5. CollectorUtils

CollectorUtils kiegészíti a szabványt Gyűjtők számos hasznos gyűjtői módszer hozzáadásával.

5.1. maxBy () és minBy ()

maxBy ()a mellékelt vetítési logika alapján megtalálja a maximális értéket egy adatfolyamban:

Stream klubok = Stream.of ("Juventus", "Barcelona", "PSG"); Választható longestName = klubok.collect (CollectorUtils.maxBy (String :: hossz)); assertThat (leghosszabbNév). tartalmaz ("Barcelona");

Ellentétben, minBy ()a mellékelt vetítési logika alapján megtalálja a minimális értéket.

5.2. egyedi()

A egyedi() gyűjtő nagyon egyszerű dolgot tesz: akkor adja vissza az egyetlen értéket, ha egy adott adatfolyamnak pontosan 1 eleme van:

Stream singleElement = Stream.of (1); Opcionális egyedi = singleElement.collect (CollectorUtils.unique ()); assertThat (egyedi). tartalmaz (1); 

Másképp, egyedi() kivételt vet:

Stream multipleElement = Stream.of (1, 2, 3); assertThatExceptionOfType (NonUniqueValueException.class) .isThrownBy (() -> {multipleElement.collect (CollectorUtils.unique ());}); 

6. Következtetés

Ebben a cikkben megtudtuk, hogyan bővíti a Protonpack könyvtár a Java Stream API-t a könnyebb használat érdekében. Hasznos módszereket ad hozzá, amelyeket általában használunk, de hiányoznak a szokásos API-ból.

A Java 9-től kezdve a Protonpack által biztosított néhány funkció elérhető lesz a standard Stream API-ban.

Szokás szerint a kód megtalálható a Githubon.