Java 8 a nekonečné prúdy

1. Prehľad

V tomto článku sa pozrieme na java.util.Stream API a uvidíme, ako môžeme tento konštrukt použiť na fungovanie na nekonečnom prúde údajov / prvkov.

Možnosť pracovať na nekonečnom slede prvkov sa zakladá na skutočnosti, že prúdy sú stavané ako lenivé.

Táto lenivosť sa dosahuje oddelením medzi dvoma typmi operácií, ktoré sa dajú vykonať na prúdoch: medziprodukt a terminál operácie.

2. Medzispotreba a terminál

Všetky Prúd operácie sa delia na medziprodukt a terminál operácie a sú spojené tak, že vytvárajú potrubní rozvody.

Potrubie toku pozostáva zo zdroja (napríklad a Zbierka, pole, funkcia generátora, I / O kanál alebo generátor nekonečnej sekvencie); nasleduje nulová alebo viac prechodných operácií a terminálna operácia.

2.1. Stredne pokročilý Operácie

Stredne pokročilý operácie sa nevykonávajú niektoré jednotky terminál operácia je vyvolaná.

Skladajú sa z potrubia a Prúd exekúcia. The medziprodukt operáciu je možné pridať do a Prúd potrubie metódami:

  • filter ()
  • mapa ()
  • flatMap ()
  • odlišný()
  • zoradené ()
  • nahliadnuť ()
  • limit ()
  • preskočiť ()

Všetky Stredne pokročilý operácie sú lenivé, takže sa nevykonajú, kým nie je skutočne potrebný výsledok spracovania.

V podstate medziprodukt operácie vrátia nový prúd. Vykonanie sprostredkujúcej operácie v skutočnosti nevykoná žiadnu operáciu, ale vytvorí nový prúd, ktorý pri prechode obsahuje prvky počiatočného toku, ktoré zodpovedajú danému predikátu.

Ako taký, priechod Prúd nezačne až do terminál prevádzka potrubia.

Toto je veľmi dôležitá vlastnosť, zvlášť dôležitá pre nekonečné prúdy - pretože nám umožňuje vytvárať prúdy, ktoré sa v skutočnosti vyvolajú iba vtedy, keď Terminál operácia sa volá.

2.2. Terminál Operácie

Terminál operácie môžu prechádzať prúdom a produkovať výsledok alebo vedľajší účinok.

Po vykonaní terminálovej operácie sa tok prúdu považuje za spotrebovaný a už ho nie je možné použiť. Takmer vo všetkých prípadoch sú terminálové operácie nedočkavé, pred návratom dokončia prechod zdrojom údajov a spracovanie potrubia.

Dychtivosť terminálovej operácie je dôležitá, pokiaľ ide o nekonečné prúdy, pretože v okamihu spracovania si musíme dobre premyslieť, či Prúd je správne ohraničenýnapríklad a limit () transformácia. Terminál operácie sú:

  • pre každý()
  • forEachOrdered ()
  • toArray ()
  • znížiť ()
  • zbierať ()
  • min ()
  • max ()
  • count ()
  • anyMatch ()
  • allMatch ()
  • noneMatch ()
  • findFirst ()
  • findAny ()

Každá z týchto operácií spustí vykonávanie všetkých prechodných operácií.

3. Nekonečné prúdy

Teraz, keď chápeme tieto dva pojmy - Stredne pokročilý a Terminál operácie - sme schopní napísať nekonečný prúd, ktorý využíva lenivosť prúdov.

Povedzme, že chceme vytvoriť nekonečný prúd prvkov od nuly, ktorý sa zvýši o dva. Potom musíme obmedziť túto postupnosť pred volaním operácie terminálu.

Rozhodujúce je použitie a limit () metóda pred vykonaním a zbierať () metóda to je operácia terminálu, inak bude náš program bežať neurčito:

// daný Stream infiniteStream = Stream.iterate (0, i -> i + 2); // keď List collect = infiniteStream .limit (10) .collect (Collectors.toList ()); // potom assertEquals (collect, Arrays.asList (0, 2, 4, 6, 8, 10, 12, 14, 16, 18));

Vytvorili sme nekonečný prúd pomocou iterovať () metóda. Potom sme zavolali a limit () transformácia a a zbierať () terminálna prevádzka. Potom v našom výslednom Zoznam, budeme mať prvých 10 prvkov nekonečnej postupnosti kvôli lenivosti a Prúd.

4. Nekonečný prúd vlastného typu prvkov

Povedzme, že chceme vytvoriť nekonečný prúd náhodných prvkov UUID.

Prvý krok k dosiahnutiu tohto použitia Prúd API je vytvoriť Dodávateľ z týchto náhodných hodnôt:

Dodávateľ randomUUIDSupplier = UUID :: randomUUID;

Keď definujeme dodávateľa, môžeme vytvoriť nekonečný prúd pomocou a generovať () metóda:

Stream infiniteStreamOfRandomUUID = Stream.generate (randomUUIDSupplier);

Potom by sme mohli vziať pár prvkov z tohto prúdu. Musíme pamätať na použitie a limit () metóda, ak chceme, aby náš program skončil v konečnom čase:

Zoznam randomInts = infiniteStreamOfRandomUUID .skip (10) .limit (10) .collect (Collectors.toList ());

Používame a preskočiť () transformáciou zahodíte prvých 10 výsledkov a vezmete ďalších 10 prvkov. Môžeme vytvoriť nekonečný prúd ľubovoľných prvkov vlastného typu odovzdaním funkcie a Dodávateľ rozhranie k a generovať () metóda na a Prúd.

6. Do-zatiaľ - prúdová cesta

Povedzme, že máme v našom kóde jednoduchú slučku do.. while:

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

Tlačíme i počítadlo desaťkrát. Môžeme očakávať, že takýto konštrukt možno ľahko napísať pomocou Prúd API a v ideálnom prípade by sme mali a doWhile () metóda na streame.

Bohužiaľ, v streame takáto metóda neexistuje a keď chceme dosiahnuť funkčnosť podobnú štandardu do-zatiaľ slučku musíme použiť a limit () metóda:

Celé čísla streamu = Stream .iterate (0, i -> i + 1); celé čísla .limit (10) .forEach (System.out :: println);

Dosiahli sme rovnakú funkcionalitu ako slučka imperatívu while s menším počtom kódov, ale volanie do limit () funkcia nie je taká popisná, ako by bola, keby sme mali a doWhile () metóda na a Prúd objekt.

5. Záver

Tento článok vysvetľuje, ako môžeme používať Stream API na vytvorenie nekonečných prúdov. Tieto, ak sa používajú spolu s transformáciami ako napr limit () - môže niektoré scenáre trochu ľahšie pochopiť a implementovať.

Kód podporujúci všetky tieto príklady nájdete v projekte GitHub - toto je projekt Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


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