Hogyan tároljuk a duplikált kulcsokat a Java térképén?
1. Áttekintés
Ebben az oktatóanyagban megvizsgáljuk a Térkép duplikált kulcsokkal, vagy más szavakkal: a Térkép amely lehetővé teszi egyetlen kulcs több értékének tárolását.
2. Normál térképek
A Java a felület több megvalósításával rendelkezik Térkép, mindegyiknek megvan a maga sajátossága.
Azonban, a meglévő Java core Map implementációk egyike sem engedi meg a Térkép több kulcs kezeléséhez egyetlen kulcshoz.
Mint láthatjuk, ha megpróbálunk két értéket beilleszteni ugyanahhoz a kulcshoz, a második érték tárolásra kerül, míg az első eldobásra kerül.
Visszaadja azt is (a program minden megfelelő megvalósításával) put (K kulcs, V érték) módszer):
Térképtérkép = új HashMap (); assertThat (map.put ("kulcs1", "érték1")). isEqualTo (null); assertThat (map.put ("kulcs1", "érték2")). isEqualTo ("érték1"); assertThat (map.get ("kulcs1")). isEqualTo ("érték2");
Hogyan érhetjük el akkor a kívánt viselkedést?
3. Gyűjtés mint érték
Nyilvánvaló, hogy a Gyűjtemény minden értékünkért Térkép elvégezné a munkát:
Térkép térkép = új HashMap (); Lista lista = new ArrayList (); map.put ("kulcs1", lista); map.get ("key1"). add ("value1"); map.get ("key1"). add ("value2"); assertThat (map.get ("kulcs1"). get (0)). isEqualTo ("érték1"); assertThat (map.get ("kulcs1"). get (1)). isEqualTo ("érték2");
Ennek a sokoldalú megoldásnak azonban számos hátránya van, és hajlamos a hibákra. Ez azt jelenti, hogy be kell mutatnunk a Gyűjtemény minden értéknél ellenőrizze annak meglétét, mielőtt hozzáadna vagy eltávolítana egy értéket, manuálisan törölje, ha nem marad érték, stb.
Java 8-ból kihasználhatjuk a kiszámít() módszereket és javítani:
Térkép térkép = új HashMap (); map.computeIfAbsent ("key1", k -> new ArrayList ()). add ("value1"); map.computeIfAbsent ("key1", k -> new ArrayList ()). add ("value2"); assertThat (map.get ("kulcs1"). get (0)). isEqualTo ("érték1"); assertThat (map.get ("kulcs1"). get (1)). isEqualTo ("érték2");
Bár ezt érdemes tudni, el kell kerülnünk, kivéve, ha nagyon jó oka van rá, mint például a korlátozó vállalati irányelvek, amelyek megakadályozzák, hogy külső könyvtárakat használjunk.
Egyébként, mielőtt megírnánk a saját szokásunkat Térkép A kerék újratelepítéséhez és újratalálásához a dobozon kívüli többféle lehetőség közül kell választanunk.
4. Apache Commons Gyűjtemények
Mint általában, Apache van megoldása a problémánkra.
Kezdjük azzal, hogy importáljuk a Közös Gyűjtemények (CC ezentúl):
org.apache.commons commons-gyűjtemények4 4.1
4.1. MultiMap
A org.apache.commons.collections4.MultiMap Az interfész meghatároz egy olyan térképet, amely értékek gyűjteményét tartja az egyes kulcsokhoz képest.
A org.apache.commons.collections4.map.MultiValueMap osztály, amely automatikusan kezeli a főzőlap nagy részét a motorháztető alatt:
MultiMap map = új MultiValueMap (); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték2"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .contains ("érték1", "érték2");
Míg ez az osztály a CC 3.2 óta elérhető, ez nem szálbiztos, és a CC 4.1-ben elavult. Csak akkor használjuk, ha nem tudunk frissíteni az újabb verzióra.
4.2. MultiValuedMap
Utódja MultiMap az a org.apache.commons.collections4.MultiValuedMap felület. Több felhasználásra kész megvalósítással rendelkezik.
Nézzük meg, hogyan tárolhatjuk több értékünket egy Tömb lista, amely megtartja a duplikátumokat:
MultiValuedMap map = new ArrayListValuedHashMap (); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték2"); map.put ("kulcs1", "érték2"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .containsExactly ("érték1", "érték2", "érték2");
Alternatív megoldásként használhatjuk a HashSet, amely duplikátumokat dob le:
MultiValuedMap map = new HashSetValuedHashMap (); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték1"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .containsExactly ("érték1");
Mindkettő a fenti megvalósítások nem biztonságosak a menetben.
Lássuk, hogyan használhatjuk a UnmodifiableMultiValuedMap dekoratőr, hogy megváltoztathatatlan legyen:
@Test (várható = UnsupportedOperationException.class) public void givenUnmodifiableMultiValuedMap_whenInserting_thenThrowingException () {MultiValuedMap map = new ArrayListValuedHashMap (); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték2"); MultiValuedMap immutableMap = MultiMapUtils.unmodifiableMultiValuedMap (térkép); immutableMap.put ("kulcs1", "érték3"); }
5. Guava Multimap
A Guava a Google Core Libraries for Java API.
A com.google.common.collect.Multimap felület a 2. verzió óta van. A cikk írásakor a legfrissebb kiadás a 25-ös, de mivel a 23. verzió után különböző jre és android (25,0 jre és 25.0-android), példáinkra továbbra is a 23. verziót fogjuk használni.
Kezdjük azzal, hogy importáljuk a Guava projektünket:
com.google.guava guava 23.0
Guava a kezdetek óta követte a többszörös megvalósítás útját.
A leggyakoribb az com.google.common.collect.ArrayListMultimap, amely a HashMap támogatta egy Tömb lista minden értékre:
Többtérképes térkép = ArrayListMultimap.create (); map.put ("kulcs1", "érték2"); map.put ("kulcs1", "érték1"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .containsExactly ("érték2", "érték1");
Mint mindig, a Multimap felület változhatatlan megvalósításait részesítjük előnyben: com.google.common.collect.ImmutableListMultimap és com.google.common.collect.ImmutableSetMultimap.
5.1. Közös térképes megvalósítások
Amikor szükségünk van egy konkrétra Térkép megvalósítás, az első dolog, hogy ellenőrizze, hogy létezik-e, mert valószínűleg Guava már megvalósította.
Például használhatjuk a com.google.common.collect.LinkedHashMultimap, amely megőrzi a kulcsok és értékek beszúrási sorrendjét:
Multimap map = LinkedHashMultimap.create (); map.put ("kulcs1", "érték3"); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték2"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .containsExactly ("érték3", "érték1", "érték2");
Alternatív megoldásként használhatjuk a com.google.common.collect.FaMultimap, amely a kulcsokat és értékeket a természetes sorrendben iterálja:
Többtérképes térkép = TreeMultimap.create (); map.put ("kulcs1", "érték3"); map.put ("kulcs1", "érték1"); map.put ("kulcs1", "érték2"); assertThat ((Gyűjtemény) map.get ("kulcs1")) .containsExactly ("érték1", "érték2", "érték3");
5.2. Kovácsolás szokásunk MultiMap
Sok más megvalósítás áll rendelkezésre.
Érdemes azonban díszíteni a Térkép és / vagy a Lista még meg nem valósult.
Szerencsére Guavának van egy gyári módszere, amely lehetővé teszi számunkra, hogy ezt megtegyük: a Multimap.newMultimap ().
6. Következtetés
Láttuk, hogyan tárolhat egy kulcs több értékét a térképen az összes létező főbb módon.
Megvizsgáltuk az Apache Commons Collections és a Guava legnépszerűbb megvalósításait, amelyeket lehetőség szerint előnyben kell részesíteni az egyedi megoldások helyett.
Mint mindig, a teljes forráskód elérhető a Githubon.