Java 8 en Infinite Streams

1. Overzicht

In dit artikel zullen we kijken naar een java.util.Stream API en we zullen zien hoe we die constructie kunnen gebruiken om te werken op een oneindige stroom gegevens / elementen.

De mogelijkheid om aan de oneindige reeks elementen te werken, is gebaseerd op het feit dat streams zijn gebouwd om lui te zijn.

Deze luiheid wordt bereikt door een scheiding tussen twee soorten operaties die op streams kunnen worden uitgevoerd: tussenproduct en terminal operaties.

2. Tussen- en terminalactiviteiten

Alle Stroom operaties zijn onderverdeeld in tussenproduct en terminal operaties en worden gecombineerd om stroompijpleidingen te vormen.

Een streampijplijn bestaat uit een bron (zoals een Verzamelingeen array, een generatorfunctie, een I / O-kanaal of een oneindige sequentiegenerator); gevolgd door nul of meer tussenliggende bewerkingen en een terminalbewerking.

2.1. Gemiddeld Operaties

Gemiddeld operaties worden niet uitgevoerd terminal operatie wordt aangeroepen.

Ze zijn samengesteld en vormen een pijplijn van een Stroom executie. De tussenproduct bewerking kan worden toegevoegd aan een Stroom pijplijn volgens methoden:

  • filter()
  • kaart()
  • flatMap ()
  • onderscheiden ()
  • gesorteerd ()
  • kijkje()
  • limiet()
  • overspringen()

Alle Gemiddeld bewerkingen zijn lui, dus ze worden pas uitgevoerd als een resultaat van een verwerking echt nodig is.

Eigenlijk, tussenproduct operaties retourneren een nieuwe stream. Het uitvoeren van een tussenliggende bewerking voert in feite geen bewerking uit, maar creëert in plaats daarvan een nieuwe stroom die, wanneer deze wordt doorlopen, de elementen van de initiële stroom bevat die overeenkomen met het gegeven predikaat.

Als zodanig traversal van de Stroom begint pas op de terminal operatie van de pijplijn wordt uitgevoerd.

Dat is een zeer belangrijke eigenschap, vooral belangrijk voor oneindige streams - omdat het ons in staat stelt streams te creëren die alleen daadwerkelijk worden aangeroepen wanneer een Terminal operatie wordt aangeroepen.

2.2. Terminal Operaties

Terminal operaties kunnen de stroom doorkruisen om een ​​resultaat of een bijwerking te produceren.

Nadat de terminaloperatie is uitgevoerd, wordt de stroompijpleiding als verbruikt beschouwd en kan deze niet langer worden gebruikt. In bijna alle gevallen zijn terminaloperaties gretig, voltooien ze hun doorgang door de gegevensbron en verwerken ze de pijplijn voordat ze terugkeren.

De gretigheid van een terminaloperatie is belangrijk met betrekking tot oneindige stromen omdat op het moment van verwerking moeten we goed nadenken of onze Stroom correct wordt begrensd door, bijvoorbeeld een limiet() transformatie. Terminal operaties zijn:

  • voor elke ()
  • forEachOrdered ()
  • toArray ()
  • verminderen()
  • verzamelen()
  • min ()
  • max ()
  • tellen ()
  • anyMatch ()
  • allMatch ()
  • noneMatch ()
  • findFirst ()
  • findAny ()

Elk van deze bewerkingen zal de uitvoering van alle tussenliggende bewerkingen activeren.

3. Oneindige stromen

Nu we deze twee concepten begrijpen - Gemiddeld en Terminal bewerkingen - we zijn in staat om een ​​oneindige stroom te schrijven die de luiheid van Streams gebruikt.

Laten we zeggen dat we een oneindige stroom elementen vanaf nul willen creëren die met twee wordt opgehoogd. Vervolgens moeten we die reeks beperken voordat we de terminaloperatie aanroepen.

Het is cruciaal om een limiet() methode voordat u een verzamelen() methode dat is een terminaloperatie, anders loopt ons programma voor onbepaalde tijd:

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

We hebben een oneindige stream gemaakt met een herhalen() methode. Toen belden we een limiet() transformatie en een verzamelen() terminal operatie. Dan in onze resulterende Lijst, we zullen de eerste 10 elementen van een oneindige reeks hebben vanwege een luiheid van a Stroom.

4. Oneindige stroom van een aangepast type elementen

Laten we zeggen dat we een oneindige stroom willekeurig willen creëren UUID's.

De eerste stap om dit te bereiken met Stroom API is om een Leverancier van die willekeurige waarden:

Leverancier randomUUIDSupplier = UUID :: randomUUID;

Wanneer we een leverancier definiëren, kunnen we een oneindige stroom creëren met behulp van een genereren () methode:

Stream infiniteStreamOfRandomUUID = Stream.generate (randomUUIDSupplier);

Dan kunnen we een paar elementen uit die stroom halen. We moeten onthouden dat we een limiet() methode als we willen dat ons programma binnen een eindige tijd eindigt:

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

We gebruiken een overspringen() transformatie om de eerste 10 resultaten weg te gooien en de volgende 10 elementen te nemen. We kunnen een oneindige stroom van elk aangepast type-element maken door een functie van een Leverancier interface naar een genereren () methode op een Stroom.

6. Doen terwijl - de Stream Way

Laten we zeggen dat we een simpele do.. while-lus in onze code hebben:

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

We zijn aan het printen ik teller tien keer. We kunnen verwachten dat een dergelijke constructie gemakkelijk kan worden geschreven met Stroom API en idealiter zouden we een doen terwijl() methode op een stream.

Helaas is er geen dergelijke methode op een stream en wanneer we functionaliteit willen bereiken die vergelijkbaar is met de standaard doen terwijl lus moeten we een limiet() methode:

Stroom gehele getallen = Stream .iterate (0, i -> i + 1); gehele getallen .limit (10) .forEach (System.out :: println);

We hebben dezelfde functionaliteit bereikt als een imperatief while-lus met minder code, maar roep de limiet() functie is niet zo beschrijvend als het zou zijn als we een doen terwijl() methode op een Stroom voorwerp.

5. Conclusie

In dit artikel wordt uitgelegd hoe we de Stream API om oneindige stromen te creëren. Deze worden samen met transformaties zoals limiet() - kan sommige scenario's een stuk gemakkelijker maken om te begrijpen en te implementeren.

De code die al deze voorbeelden ondersteunt, is te vinden in het GitHub-project - dit is een Maven-project, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.


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