Java 8 és végtelen adatfolyamok

1. Áttekintés

Ebben a cikkben megvizsgáljuk a java.util.Stream API és meglátjuk, hogyan használhatjuk ezt a konstrukciót az adatok / elemek végtelen áramán való működésre.

A végtelen elemsorozaton való munkavégzés lehetősége azon a tényen alapul, hogy a folyamokat lustának építik.

Ezt a lustaságot úgy érik el, hogy kétféle műveletet különítenek el, amelyeket streameken lehet végrehajtani: közbülső és terminál tevékenységek.

2. Közbenső és terminálműveletek

Minden Folyam műveletek vannak osztva közbülső és terminál tevékenységek és egyesítik, hogy áramló csővezetékeket képezzenek.

A folyamvezeték egy forrásból áll (például a Gyűjtemény, tömb, generátor funkció, I / O csatorna vagy végtelen szekvencia generátor); amelyet nulla vagy több közbenső művelet és egy terminálművelet követ.

2.1. Közbülső Tevékenységek

Közbülső műveletek nem hajtják végre egység terminál művelet hívódik meg.

Összeállítják az a csővezetékét Folyam végrehajtás. A közbülső művelet hozzáadható a Folyam csővezeték módszerekkel:

  • szűrő()
  • térkép()
  • flatMap ()
  • különböző()
  • rendezve ()
  • kandikál()
  • határ()
  • kihagy ()

Minden Közbülső a műveletek lusták, ezért csak a feldolgozás eredményére van szükség.

Alapvetően, közbülső műveletek új adatfolyamot adnak vissza. Egy köztes művelet végrehajtása valójában nem hajt végre semmilyen műveletet, hanem egy új adatfolyamot hoz létre, amely áthaladva tartalmazza a kezdeti adatfolyam azon elemeit, amelyek megfelelnek az adott állítmánynak.

Mint ilyen, a Folyam csak addig kezdődik terminál a csővezeték üzemeltetése végrehajtásra kerül.

Ez nagyon fontos tulajdonság, kifejezetten fontos a végtelen adatfolyamok számára - mert lehetővé teszi számunkra, hogy olyan folyamokat hozzunk létre, amelyekre valójában csak akkor Terminál műveletet nevezzük.

2.2. Terminál Tevékenységek

Terminál a műveletek áthaladhatnak a folyamon, hogy eredményt vagy mellékhatást eredményezzenek.

A terminál művelet végrehajtása után az áramvezeték fogyasztottnak tekinthető, és már nem használható. Szinte minden esetben a terminál műveletei lelkesek, befejezik az adatforrás bejárását és a csővezeték feldolgozását a visszatérés előtt.

A végállomás működésének lelkesedése azért fontos a végtelen folyamok miatt, mert a feldolgozás pillanatában alaposan át kell gondolnunk, ha a Folyam megfelelően határoljapéldául a határ() átalakítás. Terminál műveletek:

  • az egyes()
  • forEachOrdered ()
  • array ()
  • csökkenteni ()
  • gyűjt()
  • perc ()
  • max ()
  • számol()
  • anyMatch ()
  • allMatch ()
  • noneMatch ()
  • findFirst ()
  • findAny ()

Ezen műveletek mindegyike kiváltja az összes köztes művelet végrehajtását.

3. Végtelen folyamok

Most, hogy megértettük ezt a két fogalmat - Közbülső és Terminál műveletek - végtelen folyamot tudunk írni, amely kihasználja a patakok lustaságát.

Tegyük fel, hogy nulláról végtelen elemfolyamot akarunk létrehozni, amelyet kettővel növelünk. Ezután korlátoznunk kell ezt a sorrendet, mielőtt felhívnánk a terminál működését.

Döntő fontosságú a határ() módszer végrehajtása előtt a gyűjt() módszer ez egy terminálművelet, különben programunk a végtelenségig fog futni:

// adott Stream infiniteStream = Stream.iterate (0, i -> i + 2); // amikor a List collect = infiniteStream .limit (10) .collect (Collectors.toList ()); // majd assertEquals (gyűjt, Arrays.asList (0, 2, 4, 6, 8, 10, 12, 14, 16, 18));

Végtelen folyamot hoztunk létre egy hajtogat() módszer. Aztán felhívtuk a határ() átalakulás és a gyűjt() terminál működése. Majd az eredményünkben Lista, egy végtelen szekvencia első 10 eleme lesz az a lustaság miatt Folyam.

4. Egyedi típusú elemek végtelen folyama

Tegyük fel, hogy végtelen véletlenszerű áramot akarunk létrehozni UUID.

Az első lépés ennek eléréséhez a Folyam Az API-nak létre kell hoznia a Támogató a véletlenszerű értékek közül:

Szállító randomUUIDSupplier = UUID :: randomUUID;

Amikor meghatározunk egy beszállítót, akkor egy végtelen folyamot hozhatunk létre az a használatával generál() módszer:

Stream infiniteStreamOfRandomUUID = Stream.generate (randomUUIDSupplier);

Akkor vehetnénk pár elemet abból a patakból. Emlékeznünk kell arra, hogy a határ() módszer, ha azt akarjuk, hogy programunk véges idő alatt fejeződjön be:

List randomints = infiniteStreamOfRandomUUID .skip (10) .limit (10) .collect (Collectors.toList ());

Használjuk a kihagy () átalakítás az első 10 eredmény elvetéséhez és a következő 10 elem felvételéhez. Bármely egyedi típusú elem végtelen folyamát létrehozhatjuk az a függvény áthaladásával Támogató interfész a generál() módszer a Folyam.

6. Csinálni, miközben - a Patak útja

Tegyük fel, hogy van egy egyszerű do.. while hurok a kódunkban:

int i = 0; while (i <10) {System.out.println (i); i ++; }

Nyomtatunk én tízszer számlál. Arra számíthatunk, hogy egy ilyen konstrukciót könnyen meg lehet írni Folyam API és ideális esetben lenne egy csinálni, miközben() módszer egy adatfolyamon.

Sajnos nincs ilyen módszer egy adatfolyamon, és amikor a szabványhoz hasonló funkcionalitást szeretnénk elérni csinálni, miközben ciklust kell használnunk a határ() módszer:

Stream egész számok = Stream .iterate (0, i -> i + 1); egész számok .limit (10) .forEach (System.out :: println);

Ugyanolyan funkcionalitást értünk el, mint egy kötelező ciklus, kevesebb kóddal, de hívjuk a határ() függvény nem annyira leíró, mint ha lenne egy csinálni, miközben() módszer a Folyam tárgy.

5. Következtetés

Ez a cikk elmagyarázza, hogyan használhatjuk a Stream API hogy végtelen patakokat hozzon létre. Ezeket, ha olyan transzformációkkal együtt használjuk, mint pl határ () - néhány forgatókönyvet kissé könnyebben megérthet és megvalósíthat.

Az összes ilyen példát támogató kód megtalálható a GitHub projektben - ez egy Maven projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.


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