Ako ukladať duplicitné kľúče na mapu v Jave?

1. Prehľad

V tomto výučbe preskúmame dostupné možnosti pre prácu s a Mapa s duplikátmi kľúčov alebo, inými slovami, a Mapa ktorý umožňuje ukladanie viacerých hodnôt pre jeden kľúč.

2. Štandardné mapy

Java má niekoľko implementácií rozhrania Mapa, každý z nich má svoje vlastné osobitosti.

Avšak žiadna z existujúcich implementácií základnej mapy Java neumožňuje a Mapa na spracovanie viacerých hodnôt pre jeden kľúč.

Ako vidíme, ak sa pokúsime vložiť dve hodnoty pre ten istý kľúč, druhá hodnota sa uloží, zatiaľ čo prvá sa zruší.

Bude tiež vrátený (pri každej správnej implementácii put (kláves K, hodnota V) metóda):

Mapová mapa = nová HashMap (); assertThat (map.put ("key1", "value1")). isEqualTo (null); assertThat (map.put ("kľúč1", "hodnota2")). isEqualTo ("hodnota1"); assertThat (map.get ("key1")). isEqualTo ("value2"); 

Ako potom môžeme dosiahnuť požadované správanie?

3. Zbierka ako hodnota

Je zrejmé, že použitie a Zbierka za každú našu hodnotu Mapa urobil by prácu:

Mapa mapa = nová HashMap (); Zoznam zoznam = nový ArrayList (); map.put ("key1", zoznam); map.get ("key1"). add ("value1"); map.get ("kľúč1"). add ("hodnota2"); assertThat (map.get ("key1"). get (0)). isEqualTo ("value1"); assertThat (map.get ("key1"). get (1)). isEqualTo ("value2"); 

Toto podrobné riešenie má však niekoľko nevýhod a je náchylné na chyby. Znamená to, že musíme vytvoriť inštanciu a Zbierka pre každú hodnotu skontrolujte jej prítomnosť pred pridaním alebo odstránením hodnoty, vymažte ju manuálne, ak nezostanú žiadne hodnoty, atď.

Z Java 8 by sme mohli využívať vypočítať () metódy a vylepšiť ich:

Mapa mapa = nová HashMap (); map.computeIfAbsent ("key1", k -> new ArrayList ()). add ("value1"); map.computeIfAbsent ("key1", k -> new ArrayList ()). add ("value2"); assertThat (map.get ("key1"). get (0)). isEqualTo ("value1"); assertThat (map.get ("key1"). get (1)). isEqualTo ("value2"); 

Aj keď je to niečo, čo stojí za to vedieť, mali by sme sa mu vyhnúť, pokiaľ na to nemáme veľmi dobrý dôvod, napríklad obmedzujúce zásady spoločnosti, ktoré nám bránia v používaní knižníc tretích strán.

Inak skôr, ako napíšete náš vlastný zvyk Mapa implementáciu a znovuobjavenie kolesa, mali by sme si vybrať z niekoľkých možností, ktoré sú k dispozícii ihneď po vybalení.

4. Zbierky Apache Commons

Ako zvyčajne, Apache má riešenie nášho problému.

Začnime importom najnovšej verzie aplikácie Spoločné zbierky (CC odteraz):

 org.apache.commons commons-collections4 4.1 

4.1. MultiMap

The org.apache.commons.collections4.MultiMap rozhranie definuje mapu, ktorá obsahuje zbierku hodnôt proti každému kľúču.

Je implementovaná org.apache.commons.collections4.map.MultiValueMap triedy, ktorá automaticky zvládne väčšinu varných platní pod kapotou:

Mapa MultiMap = nová MultiValueMap (); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota2"); assertThat ((Collection) map.get ("key1")) .contains ("value1", "value2"); 

Aj keď je táto trieda k dispozícii od verzie CC 3.2, nie je to bezpečné pre vláknaa v CC 4.1 je zastaraná. Mali by sme ho používať, iba ak nemôžeme inovovať na novšiu verziu.

4.2. MultiValuedMap

Nástupca spoločnosti MultiMap je org.apache.commons.collections4.MultiValuedMap rozhranie. Má niekoľko implementácií pripravených na použitie.

Pozrime sa, ako uložiť naše viaceré hodnoty do súboru ArrayList, ktorý uchováva duplikáty:

Mapa MultiValuedMap = nový ArrayListValuedHashMap (); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota2"); map.put ("kľúč1", "hodnota2"); assertThat ((Collection) map.get ("key1")) .containsExactly ("value1", "value2", "value2"); 

Prípadne by sme mohli použiť a HashSet, ktorý vylučuje duplikáty:

Mapa MultiValuedMap = nová HashSetValuedHashMap (); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota1"); assertThat ((Collection) map.get ("key1")) .containsExactly ("value1"); 

Obaja vyššie implementácie nie sú bezpečné pre vlákna.

Pozrime sa, ako môžeme použiť UnmodifiableMultiValuedMap natierač, aby boli nemenné:

@Test (očakáva sa = UnsupportedOperationException.class) public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException () {MultiValuedMap mapa = nový ArrayListValuedHashMap (); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota2"); MultiValuedMap immutableMap = MultiMapUtils.unmodifiableMultiValuedMap (mapa); immutableMap.put ("kľúč1", "hodnota3"); } 

5. Guava Multimap

Guava je základné knižnice Google pre rozhranie Java API.

The com.google.common.collect.Multimap rozhranie existuje od verzie 2. V čase písania tohto článku je posledným vydaním 25, ale pretože po verzii 23 bolo rozdelené do rôznych vetiev pre jre a Android (25,0-jre a 25,0-android), pre svoje príklady budeme stále používať verziu 23.

Začnime importom Guavy do nášho projektu:

 com.google.guava guava 23.0 

Guava od začiatku nasledoval cestu viacerých implementácií.

Najbežnejším z nich je com.google.common.collect.ArrayListMultimap, ktorá používa a HashMap krytá an ArrayList pre každú hodnotu:

Multimapová mapa = ArrayListMultimap.create (); map.put ("kľúč1", "hodnota2"); map.put ("kľúč1", "hodnota1"); assertThat ((Collection) map.get ("key1")) .containsExactly ("value2", "value1"); 

Ako vždy by sme mali uprednostňovať nemenné implementácie rozhrania Multimap: com.google.common.collect.ImmutableListMultimap a com.google.common.collect.ImmutableSetMultimap.

5.1. Spoločné implementácie máp

Keď potrebujeme konkrétnu Mapa implementácia, prvá vec, ktorú musíte urobiť, je skontrolovať, či existuje, pretože pravdepodobne ju už Guava implementovala.

Napríklad môžeme použiť com.google.common.collect.LinkedHashMultimap, ktorá zachováva poradie vkladania kľúčov a hodnôt:

Multimapová mapa = LinkedHashMultimap.create (); map.put ("kľúč1", "hodnota3"); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota2"); assertThat ((Collection) map.get ("key1")) .containsExactly ("value3", "value1", "value2"); 

Prípadne môžeme použiť a com.google.common.collect.TreeMultimap, ktorý iteruje kľúče a hodnoty v ich prirodzenom poradí:

Multimapová mapa = TreeMultimap.create (); map.put ("kľúč1", "hodnota3"); map.put ("kľúč1", "hodnota1"); map.put ("kľúč1", "hodnota2"); assertThat ((Collection) map.get ("key1")) .containsExactly ("hodnota1", "hodnota2", "hodnota3"); 

5.2. Kovanie naše vlastné MultiMap

K dispozícii je mnoho ďalších implementácií.

Možno však budeme chcieť vyzdobiť a Mapa a / alebo a Zoznam zatiaľ neimplementované.

Našťastie má Guava továrenskú metódu, ktorá nám umožňuje: Multimap.newMultimap ().

6. Záver

Videli sme, ako ukladať viac hodnôt kľúča na mapu všetkými hlavnými existujúcimi spôsobmi.

Preskúmali sme najobľúbenejšie implementácie Apache Commons Collections a Guava, ktoré by sa mali uprednostniť pred vlastnými riešeniami, pokiaľ je to možné.

Celý zdrojový kód je ako vždy k dispozícii na stránkach Github.


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