Java 8 i beskonačni tokovi

1. Pregled

U ovom ćemo članku pogledati java.util.Stream API i vidjet ćemo kako možemo koristiti tu konstrukciju za rad na beskonačnom toku podataka / elemenata.

Mogućnost rada na beskonačnom slijedu elemenata temelji se na činjenici da su potoci građeni da budu lijeni.

Ta se lijenost postiže razdvajanjem dviju vrsta operacija koje bi se mogle izvesti na potocima: srednji i terminal operacijama.

2. Srednje i terminalne operacije

svi Stream operacije se dijele na srednji i terminal operacijama te se kombiniraju kako bi tvorili tekuće cjevovode.

Strujni cjevovod sastoji se od izvora (kao što je Kolekcija, niz, funkcija generatora, I / O kanal ili generator beskonačne sekvence); nakon čega slijedi nula ili više posrednih operacija i terminalna operacija.

2.1. Srednji Operacije

Srednji operacije se ne izvršavaju jedinica neke terminal poziva se operacija.

Sastavljeni su tvoreći cjevovod od Stream izvršenje. The srednji operacija se može dodati u Stream cjevovod metodama:

  • filtar()
  • karta()
  • flatMap ()
  • različit ()
  • sortirano ()
  • zaviriti ()
  • ograničiti()
  • preskočiti()

svi Srednji operacije su lijene, pa se ne izvršavaju dok stvarno nije potreban rezultat obrade.

U osnovi, srednji operacije vraćaju novi tok. Izvršavanje posredne operacije zapravo ne izvodi nijednu operaciju, već umjesto toga stvara novi tok koji, kad se pređe, sadrži elemente početnog toka koji odgovaraju danom predikatu.

Kao takav, prelazak s Stream započinje tek terminal izvodi se rad cjevovoda.

To je vrlo važno svojstvo, posebno važno za beskonačne tokove - jer nam omogućuje stvaranje streamova koji će se zapravo pozivati ​​samo kada Terminal operacija se zove.

2.2. Terminal Operacije

Terminal operacije mogu prelaziti tok kako bi proizvele rezultat ili nuspojavu.

Nakon izvođenja operacije terminala, smatra se da je cjevovod za struju potrošen i više se ne može koristiti. Gotovo u svim slučajevima terminalne su operacije nestrpljive, dovršavajući njihovo okretanje izvora podataka i obradu cjevovoda prije povratka.

Željnost terminalne operacije važna je za beskonačne tokove jer u trenutku obrade moramo dobro razmisliti je li naš Stream je pravilno ograničeno s, na primjer, a ograničiti() preobrazba. Terminal operacije su:

  • za svakoga()
  • forEachOrdered ()
  • toArray ()
  • smanjiti()
  • prikupiti()
  • min ()
  • maks. ()
  • računati()
  • anyMatch ()
  • allMatch ()
  • noneMatch ()
  • findFirst ()
  • findAny ()

Svaka od ovih operacija pokrenut će izvršenje svih posrednih operacija.

3. Beskonačni potoci

Sad kad razumijemo ova dva pojma - Srednji i Terminal operacije - možemo napisati beskonačnu struju koja koristi lijenost Streamova.

Recimo da želimo stvoriti beskonačni tok elemenata od nule koji će se povećavati za dva. Tada moramo ograničiti taj redoslijed prije pozivanja rada terminala.

Ključno je koristiti a ograničiti() metoda prije izvođenja a prikupiti() metoda to je terminalna operacija, inače će naš program raditi neograničeno:

// zadati Stream infiniteStream = Stream.iterate (0, i -> i + 2); // kada je List collect = infiniteStream .limit (10) .collect (Collectors.toList ()); // zatim assertEquals (collect, Arrays.asList (0, 2, 4, 6, 8, 10, 12, 14, 16, 18));

Stvorili smo beskonačni tok koristeći ponoviti () metoda. Tada smo nazvali a ograničiti() transformacija i a prikupiti() rad terminala. Zatim u našem rezultirajućem Popis, imat ćemo prvih 10 elemenata beskonačnog niza zbog lijenosti a Potok.

4. Beskonačni tok prilagođene vrste elemenata

Recimo da želimo stvoriti beskonačan tok slučajnih UUID-ovi.

Prvi korak za postizanje ovog korištenja Stream API je stvoriti Dobavljač tih slučajnih vrijednosti:

Dobavljač randomUUIDSupplier = UUID :: randomUUID;

Kad definiramo dobavljača, možemo stvoriti beskonačni tok pomoću a generirati() metoda:

Stream infiniteStreamOfRandomUUID = Stream.generate (randomUUIDSupplier);

Tada bismo mogli uzeti nekoliko elemenata iz te struje. Moramo se sjetiti koristiti a ograničiti() metodom ako želimo da naš program završi u konačnom vremenu:

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

Koristimo a preskočiti() transformacija odbaciti prvih 10 rezultata i uzeti sljedećih 10 elemenata. Možemo stvoriti beskonačnu struju bilo kojeg elementa prilagođenog tipa prosljeđivanjem funkcije a Dobavljač sučelje za a generirati() metoda na a Stream.

6. Učinite-dok - Put potoka

Recimo da u našem kodu imamo jednostavnu petlju do.. while:

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

Tiskamo ja brojač deset puta. Možemo očekivati ​​da se takav konstrukt može lako napisati pomoću Stream API i idealno bi bilo da imamo doWhile () metoda na potoku.

Nažalost, takva metoda ne postoji u streamu i kada želimo postići funkcionalnost sličnu standardnoj učiniti-dok petlja koju trebamo koristiti a ograničiti() metoda:

Cijeli brojevi toka = Stream .iterate (0, i -> i + 1); cijeli brojevi .limit (10) .forEach (System.out :: println);

Postigli smo istu funkcionalnost poput imperativa while petlje s manje koda, ali poziv na ograničiti() funkcija nije toliko opisna kao što bi bila da imamo a doWhile () metoda na a Stream objekt.

5. Zaključak

Ovaj članak objašnjava kako možemo koristiti Stream API stvoriti beskonačne potoke. Oni se, kada se koriste zajedno s transformacijama poput limit () - mogu neke scenarije učiniti malo lakšima za razumijevanje i provedbu.

Kôd koji podržava sve ove primjere može se naći u projektu GitHub - ovo je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.