Werken met kaarten met behulp van streams

1. Inleiding

In deze tutorial bespreken we enkele voorbeelden van het gebruik van Java Stroomswerken met Kaarts. Het is vermeldenswaard dat sommige van deze oefeningen kunnen worden opgelost met behulp van bidirectioneel Kaart datastructuur, maar we zijn hier geïnteresseerd in een functionele benadering.

Eerst leggen we het basisidee uit waarmee we gaan werken Kaarten en Strooms. Vervolgens presenteren we een aantal verschillende problemen die ermee verband houden Kaarten en hun concrete oplossingen gebruiken Strooms.

2. Basisidee

Het belangrijkste om op te merken is dat Strooms zijn reeksen van elementen die gemakkelijk kunnen worden verkregen uit een Verzameling.

Kaarten hebben een andere structuur, met een mapping van sleutels naar waarden, zonder volgorde. Dit betekent niet dat we een Kaart structuur in verschillende sequenties die ons vervolgens in staat stellen op een natuurlijke manier te werken met de Stream API.

Laten we eens kijken naar manieren om anders te verkrijgen Verzamelings van een Kaart, die we vervolgens kunnen draaien in een Stroom:

Map someMap = nieuwe HashMap ();

We kunnen een set sleutel-waardeparen verkrijgen:

Set inzendingen = someMap.entrySet ();

We kunnen ook de sleutelset krijgen die is gekoppeld aan de Kaart:

Set keySet = someMap.keySet ();

Of we zouden rechtstreeks kunnen werken met de reeks waarden:

Verzamelingswaarden = someMap.values ​​();

Deze geven ons elk een toegangspunt om die collecties te verwerken door er streams van te verkrijgen:

Stroom entriesStream = entries.stream (); Stream valuesStream = values.stream (); Stroom keysStream = keySet.stream ();

3. Een Kaart‘S Keys gebruiken Strooms

3.1. Invoergegevens

Laten we aannemen dat we een Kaart:

Kaartboeken = nieuwe HashMap (); books.put ("978-0201633610", "Ontwerppatronen: elementen van herbruikbare objectgeoriënteerde software"); books.put ("978-1617291999", "Java 8 in actie: Lambdas, Streams en programmeren in functionele stijl"); books.put ("978-0134685991", "Effectieve Java");

We zijn geïnteresseerd in het vinden van het ISBN-nummer voor het boek met de titel "Effectieve Java".

3.2. Een match ophalen

Omdat de titel van het boek niet kon bestaan ​​in ons Kaart, willen we kunnen aangeven dat er geen bijbehorend ISBN-nummer voor is. We kunnen een Optioneel om dat uit te drukken:

Laten we voor dit voorbeeld aannemen dat we geïnteresseerd zijn in een sleutel voor een boek dat overeenkomt met die titel:

Optioneel optionalIsbn = books.entrySet (). Stream () .filter (e -> "Effectieve Java" .equals (e.getValue ())) .map (Map.Entry :: getKey) .findFirst (); assertEquals ("978-0134685991", optionalIsbn.get ());

Laten we de code analyseren. Eerste, we verkrijgen de entrySet van de Kaart, zoals we eerder zagen.

We willen alleen de items met "Effectieve Java" als titel beschouwen, dus de eerste tussenliggende bewerking zal een filter zijn.

We zijn niet geïnteresseerd in het geheel Kaart item, maar in de sleutel van elk item. Dus de volgende geketende tussenliggende operatie doet precies dat: het is een kaart bewerking die een nieuwe stream als uitvoer zal genereren die alleen de sleutels bevat voor de items die overeenkomen met de titel waarnaar we op zoek waren.

Omdat we maar één resultaat willen, kunnen we de findFirst () terminalbewerking, die de beginwaarde in de Stroom als een Optioneel voorwerp.

Laten we eens kijken naar een geval waarin een titel niet bestaat:

Optioneel optionalIsbn = books.entrySet (). Stream () .filter (e -> "Niet bestaande titel" .equals (e.getValue ())) .map (Map.Entry :: getKey) .findFirst (); assertEquals (false, optionalIsbn.isPresent ());

3.3. Meerdere resultaten ophalen

Laten we het probleem nu veranderen om te zien hoe we kunnen omgaan met het retourneren van meerdere resultaten in plaats van één.

Om meerdere resultaten te laten retourneren, voegen we het volgende boek toe aan ons Kaart:

books.put ("978-0321356680", "Effective Java: Second Edition"); 

Dus nu, als we zoeken naar alle boeken die beginnen met "Effectieve Java", krijgen we meer dan één resultaat terug:

Lijst isbnCodes = books.entrySet (). Stream () .filter (e -> e.getValue (). StartsWith ("Effective Java")) .map (Map.Entry :: getKey) .collect (Collectors.toList () ); assertTrue (isbnCodes.contains ("978-0321356680")); assertTrue (isbnCodes.contains ("978-0134685991"));

Wat we in dit geval hebben gedaan, is de filtervoorwaarde vervangen om te controleren of de waarde in de Kaart begint met "Effectieve Java" in plaats van te vergelijken voor Draad gelijkheid.

Deze keer, wij verzamelen de resultaten - in plaats van de eerste te kiezen - de lucifers in een Lijst.

4. Een Kaart‘S Waarden gebruiken Strooms

Laten we ons nu concentreren op een ander probleem met kaarten: In plaats van te verkrijgen ISBN-nummers gebaseerd op de titels, we zullen proberen en krijgen titels gebaseerd op de ISBN-nummers.

Laten we het origineel gebruiken Kaart. We willen titels vinden waarvan hun ISBN begint met "978-0".

Lijsttitels = books.entrySet (). Stream () .filter (e -> e.getKey (). StartsWith ("978-0")) .map (Map.Entry :: getValue) .collect (Collectors.toList ( )); assertEquals (2, titels.size ()); assertTrue (titels.contains ("Ontwerppatronen: elementen van herbruikbare objectgeoriënteerde software")); assertTrue (titels.contains ("Effectieve Java"));

Deze oplossing is vergelijkbaar met de oplossingen voor onze vorige reeks problemen - we streamen de ingangsset en filteren, mappen en verzamelen.

En zoals eerder, als we alleen de eerste wedstrijd wilden terugspelen, konden we na de kaart methode roep het findFirst () methode in plaats van alle resultaten te verzamelen in een Lijst.

5. Conclusie

We hebben laten zien hoe u een Kaart op een functionele manier.

In het bijzonder hebben we gezien dat zodra we overschakelen op het gebruik van de bijbehorende collecties naar Kaarts, de verwerking met Strooms wordt veel gemakkelijker en intuïtief.

En natuurlijk zijn alle voorbeelden te vinden in het GitHub-project.