Java 8 Collectors toMap

1. Inleiding

In deze korte tutorial gaan we het hebben over de in kaart brengen() methode van de Verzamelaars klasse. We zullen het gebruiken om te verzamelen Strooms in een Kaart voorbeeld.

Voor alle voorbeelden die hier worden behandeld, gebruiken we een lijst met boeken als uitgangspunt en transformeren we deze in andere Kaart implementaties.

2. Lijst naar Kaart

We beginnen met het eenvoudigste geval, door een Lijst in een Kaart.

Onze Boek klasse wordt gedefinieerd als:

class Book {private String naam; privé int releaseYear; private String isbn; // getters en setters}

En we maken een lijst met boeken om onze code te valideren:

Lijst bookList = nieuwe ArrayList (); bookList.add (nieuw boek ("The Fellowship of the Ring", 1954, "0395489318")); bookList.add (nieuw boek ("The Two Towers", 1954, "0345339711")); bookList.add (nieuw boek ("The Return of the King", 1955, "0618129111"));

Voor dit scenario gebruiken we de volgende overbelasting van het in kaart brengen() methode:

Verzamelaar toMap (Functie keyMapper, Functie valueMapper)

Met in kaart brengen, kunnen we strategieën aangeven voor het verkrijgen van de sleutel en waarde voor de kaart:

openbare kaart listToMap (List books) {return books.stream (). collect (Collectors.toMap (Book :: getIsbn, Book :: getName)); }

En we kunnen eenvoudig valideren dat het werkt met:

@Test openbare leegte whenConvertFromListToMap () {assertTrue (convertToMap.listToMap (bookList) .size () == 3); }

3. Sleutelconflicten oplossen

Het bovenstaande voorbeeld werkte goed, maar wat zou er gebeuren als er een dubbele sleutel is?

Laten we ons voorstellen dat we onze Kaart door elk Boek‘Jaar van uitgave:

openbare Map listToMapWithDupKeyError (Lijstboeken) {return books.stream (). collect (Collectors.toMap (Boek :: getReleaseYear, Function.identity ())); }

Gezien onze eerdere lijst met boeken, zouden we een IllegalStateException:

@Test (verwacht = IllegalStateException.class) openbare leegte whenMapHasDuplicateKey_without_merge_function_then_runtime_exception () {convertToMap.listToMapWithDupKeyError (bookList); }

Om dit op te lossen, moeten we een andere methode gebruiken met een extra parameter, de mergeFunction:

Collector toMap (Function keyMapper, Function valueMapper, BinaryOperator mergeFunction) 

Laten we een samenvoegfunctie introduceren die aangeeft dat we, in het geval van een botsing, de bestaande invoer behouden:

openbare Map listToMapWithDupKey (Lijstboeken) {return books.stream (). collect (Collectors.toMap (Boek :: getReleaseYear, Function.identity (), (bestaand, vervangend) -> bestaand)); }

Of, met andere woorden, we krijgen first-win-gedrag:

@Test openbare leegte whenMapHasDuplicateKeyThenMergeFunctionHandlesCollision () {Map booksByYear = convertToMap.listToMapWithDupKey (bookList); assertEquals (2, booksByYear.size ()); assertEquals ("0395489318", booksByYear.get (1954) .getIsbn ()); }

4. Andere kaarttypes

Standaard is een in kaart brengen() methode retourneert een Hash kaart.

Maar kunnen we anders terugkeren Kaart implementaties? Het antwoord is ja:

Collector toMap (Function keyMapper, Function valueMapper, BinaryOperator mergeFunction, Supplier mapSupplier)

Waar de mapSupplier is een functie die een nieuwe, lege retourneert Kaart met de resultaten.

4.1. Lijst naar ConcurrentMap

Laten we hetzelfde voorbeeld nemen als hierboven en een mapSupplier functie om een ConcurrentHashMap:

openbare kaart listToConcurrentMap (Lijst boeken) {return books.stream (). collect (Collectors.toMap (Boek :: getReleaseYear, Function.identity (), (o1, o2) -> o1, ConcurrentHashMap :: nieuw)); }

Laten we doorgaan en onze code testen:

@Test openbare leegte whenCreateConcurrentHashMap () {assertTrue (convertToMap.listToConcurrentMap (bookList) instantie van ConcurrentHashMap); }
4.2. Gesorteerd Kaart

Laten we tot slot kijken hoe we een gesorteerde kaart kunnen retourneren. Daarvoor gebruiken we een TreeMap als een mapSupplier parameter.

Omdat een TreeMap wordt standaard gesorteerd volgens de natuurlijke volgorde van de sleutels, we hoeven de boeken onszelf:

openbare TreeMap listToSortedMap (Lijstboeken) {return books.stream () .collect (Collectors.toMap (Boek :: getName, Function.identity (), (o1, o2) -> o1, TreeMap :: nieuw)); }

Dus in ons geval zijn ze teruggekeerd TreeMap wordt in alfabetische volgorde gesorteerd op de naam van het boek:

@Test openbare leegte whenMapisSorted () {assertTrue (convertToMap.listToSortedMap (bookList) .firstKey (). Equals ("The Fellowship of the Ring")); }
5. Conclusie

In dit artikel hebben we gekeken naar de in kaart brengen() methode van de Verzamelaars klasse. Het stelt ons in staat om een ​​nieuw te creëren Kaart van een Stroom. We hebben ook geleerd hoe we belangrijke conflicten kunnen oplossen en verschillende kaartimplementaties kunnen maken.

Zoals altijd is de code beschikbaar op GitHub.