Twee kaarten samenvoegen met Java 8

1. Inleiding

In deze korte tutorial, we laten zien hoe u twee kaarten samenvoegt met behulp van de Java 8-mogelijkheden.

Om specifieker te zijn, zullen we verschillende samenvoegscenario's onderzoeken, inclusief kaarten met dubbele vermeldingen.

2. Initialisatie

Laten we om te beginnen twee definiëren Kaart gevallen:

privé statische kaart map1 = nieuwe HashMap (); privé statische kaart map2 = nieuwe HashMap ();

De Werknemer klasse ziet er als volgt uit:

openbare klasse Medewerker {privé Lange id; private String naam; // constructor, getters, setters}

Vervolgens kunnen we wat gegevens naar het Kaart gevallen:

Werknemer werknemer1 = nieuwe werknemer (1L, "Henry"); map1.put (werknemer1.getNaam (), werknemer1); Werknemer werknemer2 = nieuwe werknemer (22L, "Annie"); map1.put (werknemer2.getNaam (), werknemer2); Werknemer werknemer3 = nieuwe werknemer (8L, "Jan"); map1.put (werknemer3.getNaam (), werknemer3); Werknemer werknemer4 = nieuwe werknemer (2L, "George"); map2.put (employee4.getName (), employee4); Werknemer werknemer5 = nieuwe werknemer (3L, "Henry"); map2.put (werknemer5.getNaam (), werknemer5);

Merk op dat we identieke sleutels hebben voor werknemer 1 en werknemer5 vermeldingen in onze kaarten die we later zullen gebruiken.

3. Map.merge ()

Java 8 voegt een nieuw samenvoegen() functie in de java.util.Map koppel.

Hier is hoe de samenvoegen() functie werkt: als de opgegeven sleutel nog niet aan een waarde is gekoppeld of als de waarde null is, wordt de sleutel aan de opgegeven waarde gekoppeld.

Anders vervangt het de waarde door de resultaten van de gegeven remapping-functie. Als het resultaat van de functie opnieuw toewijzen nul is, wordt het resultaat verwijderd.

Laten we eerst een nieuw Hash kaart door alle vermeldingen uit het kaart1:

Map map3 = nieuwe HashMap (map1);

Laten we vervolgens het samenvoegen() functie samen met de samenvoegregel:

map3.merge (sleutel, waarde, (v1, v2) -> nieuwe werknemer (v1.getId (), v2.getName ())

Ten slotte zullen we de kaart2 en voeg de vermeldingen samen in kaart3:

map2.forEach ((sleutel, waarde) -> map3.merge (sleutel, waarde, (v1, v2) -> nieuwe werknemer (v1.getId (), v2.getName ())));

Laten we het programma uitvoeren en de inhoud van kaart3:

John = Werknemer {id = 8, naam = "John"} Annie = Werknemer {id = 22, naam = "Annie"} George = Werknemer {id = 2, naam = "George"} Henry = Werknemer {id = 1, name = "Henry"}

Als resultaat, onze gecombineerd Kaart heeft alle elementen van de vorige Hash kaart inzendingen. Invoer met dubbele sleutels zijn samengevoegd tot één invoer.

We merken ook dat de Werknemer object van het laatste item heeft de ID kaart van de kaart1, en de waarde wordt gekozen kaart2.

Dit komt door de regel die we hebben gedefinieerd in onze fusiefunctie:

(v1, v2) -> nieuwe werknemer (v1.getId (), v2.getName ())

4. Stream.concat ()

De Stroom API in Java 8 kan ook een gemakkelijke oplossing voor ons probleem bieden. Eerste, we moeten onze combineren Kaart instanties in één Stroom. Dat is precies wat Stream.concat () operatie doet:

Stream gecombineerd = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ());

Hier geven we de kaartinvoersets door als parameters. Vervolgens moeten we ons resultaat verzamelen in een nieuw Kaart. Daar kunnen we gebruik van maken Collectors.toMap ():

Kaartresultaat = combined.collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue));

Als gevolg hiervan zal de verzamelaar de bestaande sleutels en waarden van onze kaarten gebruiken. Maar deze oplossing is verre van perfect. Zodra onze verzamelaar inzendingen met dubbele sleutels tegenkomt, gooit hij een IllegalStateException.

Om dit probleem op te lossen, voegen we eenvoudig een derde lambda-parameter "merger" toe aan onze verzamelaar:

(waarde1, waarde2) -> nieuwe werknemer (waarde2.getId (), waarde1.getNaam ())

Het zal de lambda-uitdrukking gebruiken elke keer dat een dubbele sleutel wordt gedetecteerd.

Eindelijk alles bij elkaar:

Kaartresultaat = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (waarde1 , waarde2) -> nieuwe werknemer (waarde2.getId (), waarde1.getNaam ())));

Laten we tot slot de code uitvoeren en de resultaten bekijken:

George = Werknemer {id = 2, naam = "George"} John = Werknemer {id = 8, naam = "John"} Annie = Werknemer {id = 22, naam = "Annie"} Henry = Werknemer {id = 3, name = "Henry"}

Zoals we zien, zijn de dubbele vermeldingen met de sleutel "Henry" zijn samengevoegd tot een nieuw sleutel / waarde-paar waar de id van het nieuwe Werknemer werd geplukt uit de kaart2 en de waarde van kaart1.

5. Stream.of ()

Om het Stroom API, we kunnen onze Kaart instanties in een verenigde stream met behulp van Stroom van().

Hier hoeven we geen extra collectie te maken om met de streams te werken:

Map map3 = Stream.of (map1, map2) .flatMap (map -> map.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1 , v2) -> nieuwe werknemer (v1.getId (), v2.getName ())));

Eerste, wij transformeren kaart1 en kaart2 in een enkele stroom. Vervolgens zetten we de stream om in de kaart. Zoals we kunnen zien, is het laatste argument van in kaart brengen() is een samenvoegfunctie. Het lost het probleem met dubbele sleutels op door het id-veld te kiezen uit v1 vermelding en de naam van v2.

De gedrukte kaart3 instantie na het uitvoeren van het programma:

George = Werknemer {id = 2, naam = "George"} John = Werknemer {id = 8, naam = "John"} Annie = Werknemer {id = 22, naam = "Annie"} Henry = Werknemer {id = 1, name = "Henry"}

6. Eenvoudige streaming

Bovendien kunnen we een stroom() pijplijn om onze kaartingangen samen te stellen. Het onderstaande codefragment laat zien hoe u de vermeldingen uit kaart2 en kaart1 door de dubbele vermeldingen te negeren:

Map map3 = map2.entrySet () .stream () .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1, v2) -> nieuwe medewerker (v1.getId (), v2 .getName ()), () -> nieuwe HashMap (map1)));

Zoals we verwachten, zijn de resultaten na de samenvoeging:

{John = Werknemer {id = 8, naam = "John"}, Annie = Werknemer {id = 22, naam = "Annie"}, George = Werknemer {id = 2, naam = "George"}, Henry = Werknemer { id = 1, name = "Henry"}}

7. StreamEx

Naast oplossingen die door de JDK worden geboden, kunnen we ook gebruik maken van de populaire StreamEx bibliotheek.

Simpel gezegd, StreamEx is een verbetering voor de Stroom API en biedt veel aanvullende handige methoden. We gebruiken een EntryStream instantie om te werken met sleutel-waardeparen:

Map map3 = EntryStream.of (map1) .append (EntryStream.of (map2)) .toMap ((e1, e2) -> e1);

Het idee is om de stromen van onze kaarten samen te voegen tot één. Vervolgens verzamelen we de vermeldingen in het nieuwe kaart3 voorbeeld. Belangrijk om te vermelden, de (e1, e2) -> e1 expressie omdat het helpt om de regel te definiëren voor het omgaan met de dubbele sleutels. Zonder dit zal onze code een IllegalStateException.

En nu de resultaten:

{George = Werknemer {id = 2, naam = "George"}, John = Werknemer {id = 8, naam = "John"}, Annie = Werknemer {id = 22, naam = "Annie"}, Henry = Werknemer { id = 1, name = "Henry"}}

8. Samenvatting

In dit korte artikel hebben we verschillende manieren geleerd om kaarten samen te voegen in Java 8. Meer specifiek, we gebruikten Map.merge (), Stream API, StreamEx bibliotheek.

Zoals altijd is de code die tijdens de discussie is gebruikt, te vinden op GitHub.


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