Hogyan lehet elszakadni a Java Stream-től mindkettőn

1. Áttekintés

Java fejlesztőként gyakran írunk olyan kódot, amely az elemek halmazán ismétlődik, és mindegyiken műveletet hajt végre. A Java 8 streaming könyvtár és annak az egyes módszer lehetővé teszi számunkra, hogy tiszta és deklaratív módon írjuk meg a kódot.

Bár ez hasonló a hurkokhoz, hiányzik a megfelelője szünet nyilatkozat az iteráció megszakítására. A folyam lehet nagyon hosszú, vagy potenciálisan végtelen, és ha nincs okunk tovább feldolgozni, akkor inkább el akarunk szakadni tőle, mint megvárni az utolsó elemét.

Ebben az oktatóanyagban megnézünk néhány mechanizmust szimuláljuk a szünet nyilatkozat a Stream.forMinden művelet.

2. Java 9-esek Stream.takeWhile ()

Tegyük fel, hogy van egy adatfolyamunk Húr elemeket, és elemeit addig szeretnénk feldolgozni, amíg hosszuk páratlan.

Próbáljuk ki a Java 9-et Stream. takeWhile módszer:

Stream.of ("macska", "kutya", "elefánt", "róka", "nyúl", "kacsa") .takeWhile (n -> n.hossz ()% 2! = 0) .minden (Rendszer. ki :: println);

Ha ezt futtatjuk, megkapjuk a kimenetet:

macska kutya

Hasonlítsuk össze ezt a sima Java megfelelő kódjával az a használatával mert hurok és a szünet utasítás, hogy lássa, hogyan működik:

Lista lista = asList ("macska", "kutya", "elefánt", "róka", "nyúl", "kacsa"); for (int i = 0; i <list.size (); i ++) {String item = list.get (i); if (elem.hossz ()% 2 == 0) {törés; } System.out.println (elem); } 

Mint láthatjuk, a vegyeMíg módszer lehetővé teszi számunkra, hogy pontosan azt érjük el, amire szükségünk van.

De Mi van, ha még nem fogadtuk el a Java 9-et? Hogyan érhetünk el hasonlót a Java 8 használatával?

3. Egy egyedi Elosztó

Hozzunk létre egy egyéni Elosztó hogy dekoratőrként fog működni a Stream.spliterator. Ezt elkészíthetjük Elosztó végre a szünet nekünk.

Először megkapjuk a Elosztó a mi patakunkból, majd díszítjük a miénkkel CustomSpliterator és biztosítja a Állítmány hogy ellenőrizzék a szünet művelet. Végül létrehozunk egy új adatfolyamot a CustomSpliterator:

public static Stream takeWhile (Stream stream, predikátum predikátum) {CustomSpliterator customSpliterator = új CustomSpliterator (stream.spliterator (), predikátum); return StreamSupport.stream (customSpliterator, hamis); }

Nézzük meg, hogyan lehet létrehozni CustomSpliterator:

public class CustomSpliterator kiterjeszti a Spliteratorokat.AbstractSpliterator {private Spliterator splitr; privát predikátum predikátum; privát logikai isMatched = true; public CustomSpliterator (Spliterator splitr, predikátum predikátum) {super (splitr.estimateSize (), 0); ez.splitr = splitr; ez.predikátum = állítmány; } @Orride public synchronized boolean tryAdvance (Consumer consumer) {boolean hadNext = splitr.tryAdvance (elem -> {if (predicate.test (elem) && isMatched) {consumer.accept (elem);} else {isMatched = false;} }); return hadKövetkező && isMatched; }}

Tehát vessünk egy pillantást a tryAdvance módszer. Itt láthatjuk, hogy a szokás Elosztó feldolgozza a díszített elemeket Elosztó. A feldolgozás mindaddig megtörténik, amíg az állítmányunk egyezik, és a kezdeti adatfolyamnak még vannak elemei. Amikor bármelyik feltétel bekövetkezik hamis, a mi Elosztó„Szünetek” és a streaming művelet befejeződik.

Teszteljük új segítő módszerünket:

@Test public void whenCustomTakeWhileIsCalled_ThenCorrectItemsAreReturned () {Stream initialStream = Stream.of ("macska", "kutya", "elefánt", "róka", "nyúl", "kacsa"); Lista eredménye = CustomTakeWhile.takeWhile (kezdeti adatfolyam, x -> x.length ()% 2! = 0) .collect (Collectors.toList ()); assertEquals (asList ("macska", "kutya"), eredmény); }

Mint láthatjuk, a patak a feltétel teljesülése után leállt. Tesztelés céljából összegyűjtöttük az eredményeket egy listába, de felhasználhattuk volna a az egyes hívás vagy bármely más funkciója Folyam.

4. Egy egyedi az egyes

Miközben biztosítja a Folyam a ... val szünet a beágyazott mechanizmus hasznos lehet, egyszerűbb lehet csak a az egyes művelet.

Használjuk a Stream.spliterator közvetlenül dekoratőr nélkül:

public class CustomForEach {public static class Breaker {private boolean shouldBreak = false; public void stop () {shouldBreak = true; } boolean get () {return shouldBreak; }} public static void forEach (Stream stream, BiConsumer consumer) {Spliterator spliterator = stream.spliterator (); logikai hadNext = true; Megszakító megszakító = új Megszakító (); while (hadNext &&! breaker.get ()) {hadNext = spliterator.tryAdvance (elem -> {consumer.accept (elem, breaker);}); }}}

Mint láthatjuk, az új szokás az egyes metódus a BiConsumer kódunk megadása a következő elemmel és egy megszakító objektummal, amelyet a folyam leállításához használhat.

Próbáljuk ki ezt egy egység tesztben:

@Test public void whenCustomForEachIsCalled_ThenCorrectItemsAreReturned () {Stream initialStream = Stream.of ("macska", "kutya", "elefánt", "róka", "nyúl", "kacsa"); Lista eredménye = new ArrayList (); CustomForEach.forEach (initialStream, (elem, breaker) -> {if (elem.length ()% 2 == 0) {breaker.stop ();} else {result.add (elem);}}); assertEquals (asList ("macska", "kutya"), eredmény); }

5. Következtetés

Ebben a cikkben megvizsgáltuk a hívás egyenértékű biztosításának módjait szünet patakon. Láttuk, hogy a Java 9-es vegyeMíg megoldja számunkra a legtöbb problémát, és hogy miként biztosíthatjuk annak verzióját a Java 8 esetén.

Végül megvizsgáltunk egy hasznossági módszert, amely az a-val egyenértékű számot nyújthat szünet művelet közben a Folyam.

Mint mindig, a példakód megtalálható a GitHubon.