Сравняване на две HashMaps в Java

1. Общ преглед

В този урок ще проучим различни начини за сравняване на две HashMaps в Java .

Ще обсъдим множество начини да проверим дали две HashMaps са подобни. Също така ще използваме Java 8 Stream API и Guava, за да получим подробните разлики между различните HashMaps .

2. Използване на Map.equals ()

Първо ще използваме Map.equals (), за да проверим дали две HashMaps имат едни и същи записи:

@Test public void whenCompareTwoHashMapsUsingEquals_thenSuccess() { Map asiaCapital1 = new HashMap(); asiaCapital1.put("Japan", "Tokyo"); asiaCapital1.put("South Korea", "Seoul"); Map asiaCapital2 = new HashMap(); asiaCapital2.put("South Korea", "Seoul"); asiaCapital2.put("Japan", "Tokyo"); Map asiaCapital3 = new HashMap(); asiaCapital3.put("Japan", "Tokyo"); asiaCapital3.put("China", "Beijing"); assertTrue(asiaCapital1.equals(asiaCapital2)); assertFalse(asiaCapital1.equals(asiaCapital3)); }

Тук създаваме три обекта HashMap и добавяме записи. След това използваме Map.equals (), за да проверим дали две HashMaps имат едни и същи записи.

Начинът, по който Map.equals () работи е чрез сравняване на ключове и стойности, като се използват () Object.equals метод . Това означава, че работи само когато обектите на ключ и стойност реализират правилно equals () .

Например Map.equals () не работи, когато типът стойност е масив, тъй като методът equals () на масива сравнява идентичността, а не съдържанието на масива:

@Test public void whenCompareTwoHashMapsWithArrayValuesUsingEquals_thenFail() { Map asiaCity1 = new HashMap(); asiaCity1.put("Japan", new String[] { "Tokyo", "Osaka" }); asiaCity1.put("South Korea", new String[] { "Seoul", "Busan" }); Map asiaCity2 = new HashMap(); asiaCity2.put("South Korea", new String[] { "Seoul", "Busan" }); asiaCity2.put("Japan", new String[] { "Tokyo", "Osaka" }); assertFalse(asiaCity1.equals(asiaCity2)); }

3. Използване на Java Stream API

Също така можем да внедрим собствен метод за сравняване на HashMaps, използвайки Java 8 Stream API:

private boolean areEqual(Map first, Map second) { if (first.size() != second.size()) { return false; } return first.entrySet().stream() .allMatch(e -> e.getValue().equals(second.get(e.getKey()))); }

За простота внедрихме метода areEqual () , който вече можем да използваме за сравняване на обектите на HashMap :

@Test public void whenCompareTwoHashMapsUsingStreamAPI_thenSuccess() { assertTrue(areEqual(asiaCapital1, asiaCapital2)); assertFalse(areEqual(asiaCapital1, asiaCapital3)); }

Но също така можем да персонализираме собствения си метод areEqualWithArrayValue (), за да обработваме стойностите на масива, като използваме Arrays.equals () за сравняване на два масива:

private boolean areEqualWithArrayValue(Map first, Map second) { if (first.size() != second.size()) { return false; } return first.entrySet().stream() .allMatch(e -> Arrays.equals(e.getValue(), second.get(e.getKey()))); }

За разлика от Map.equals () , нашият собствен метод успешно ще сравнява HashMaps със стойности на масива:

@Test public void whenCompareTwoHashMapsWithArrayValuesUsingStreamAPI_thenSuccess() { assertTrue(areEqualWithArrayValue(asiaCity1, asiaCity2)); assertFalse(areEqualWithArrayValue(asiaCity1, asiaCity3)); }

4. Сравнение на клавишите и стойностите на HashMap

След това нека видим как да сравним два ключа HashMap и съответните им стойности.

4.1. Сравняване на клавишите на HashMap

Първо, можем да проверим дали два HashMaps имат еднакви ключове, като просто сравним техния KeySet () :

@Test public void whenCompareTwoHashMapKeys_thenSuccess() { assertTrue(asiaCapital1.keySet().equals(asiaCapital2.keySet())); assertFalse(asiaCapital1.keySet().equals(asiaCapital3.keySet())); }

4.2. Сравняване на стойностите на HashMap

След това ще видим как да сравняваме стойностите на HashMap една по една.

Ще приложим прост метод, за да проверим кои ключове имат еднаква стойност и в двата HashMaps, използвайки Stream API:

private Map areEqualKeyValues(Map first, Map second) { return first.entrySet().stream() .collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().equals(second.get(e.getKey())))); }

Вече можем да използваме areEqualKeyValues ​​(), за да сравним две различни HashMaps, за да видим подробно кои ключове имат еднаква стойност и кои имат различни стойности:

@Test public void whenCompareTwoHashMapKeyValuesUsingStreamAPI_thenSuccess() { Map asiaCapital3 = new HashMap(); asiaCapital3.put("Japan", "Tokyo"); asiaCapital3.put("South Korea", "Seoul"); asiaCapital3.put("China", "Beijing"); Map asiaCapital4 = new HashMap(); asiaCapital4.put("South Korea", "Seoul"); asiaCapital4.put("Japan", "Osaka"); asiaCapital4.put("China", "Beijing"); Map result = areEqualKeyValues(asiaCapital3, asiaCapital4); assertEquals(3, result.size()); assertThat(result, hasEntry("Japan", false)); assertThat(result, hasEntry("South Korea", true)); assertThat(result, hasEntry("China", true)); }

5. Разлика в картата с помощта на гуава

И накрая, ще видим как да получим подробна разлика между две HashMaps, използвайки Guava Maps.difference ().

Този метод връща обект MapDifference, който има редица полезни методи за анализ на разликата между Maps. Нека да разгледаме някои от тях.

5.1. MapDifference.entriesDiffering ()

Първо, ще получим общи ключове, които имат различни стойности във всяка HashMap, използвайки MapDifference.entriesDiffering () :

@Test public void givenDifferentMaps_whenGetDiffUsingGuava_thenSuccess() { Map asia1 = new HashMap(); asia1.put("Japan", "Tokyo"); asia1.put("South Korea", "Seoul"); asia1.put("India", "New Delhi"); Map asia2 = new HashMap(); asia2.put("Japan", "Tokyo"); asia2.put("China", "Beijing"); asia2.put("India", "Delhi"); MapDifference diff = Maps.difference(asia1, asia2); Map
    
      entriesDiffering = diff.entriesDiffering(); assertFalse(diff.areEqual()); assertEquals(1, entriesDiffering.size()); assertThat(entriesDiffering, hasKey("India")); assertEquals("New Delhi", entriesDiffering.get("India").leftValue()); assertEquals("Delhi", entriesDiffering.get("India").rightValue()); }
    

Методът entriesDiffering () връща нова карта, която съдържа набор от общи ключове и обекти ValueDifference като набор от стойности.

Всеки обект ValueDifference има методи leftValue () и rightValue () , които връщат стойностите съответно в двете Карти .

5.2. MapDifference.entriesOnlyOnRight () и MapDifference.entriesOnlyOnLeft ()

След това можем да получим записи, които съществуват само в една HashMap, използвайки MapDifference.entriesOnlyOnRight () и MapDifference.entriesOnlyOnLeft ():

@Test public void givenDifferentMaps_whenGetEntriesOnOneSideUsingGuava_thenSuccess() { MapDifference diff = Maps.difference(asia1, asia2); Map entriesOnlyOnRight = diff.entriesOnlyOnRight(); Map entriesOnlyOnLeft = diff.entriesOnlyOnLeft(); assertEquals(1, entriesOnlyOnRight.size()); assertEquals(1, entriesOnlyOnLeft.size()); assertThat(entriesOnlyOnRight, hasEntry("China", "Beijing")); assertThat(entriesOnlyOnLeft, hasEntry("South Korea", "Seoul")); }

5.3. MapDifference.entriesInCommon ()

След това ще получим общи записи, използвайки MapDifference.entriesInCommon ():

@Test public void givenDifferentMaps_whenGetCommonEntriesUsingGuava_thenSuccess() { MapDifference diff = Maps.difference(asia1, asia2); Map entriesInCommon = diff.entriesInCommon(); assertEquals(1, entriesInCommon.size()); assertThat(entriesInCommon, hasEntry("Japan", "Tokyo")); }

5.4. Персонализиране на поведението на Maps.difference ()

Тъй като Maps.difference () използва equals () и hashCode () по подразбиране за сравняване на записи, няма да работи за Обекти, които не ги прилагат правилно:

@Test public void givenSimilarMapsWithArrayValue_whenCompareUsingGuava_thenFail() { MapDifference diff = Maps.difference(asiaCity1, asiaCity2); assertFalse(diff.areEqual()); }

Но можем да персонализираме използвания метод в сравнение, използвайки еквивалентност .

Например ще определим еквивалентност за тип String [], за да сравним String [] стойностите в нашите HashMaps, както ни харесва:

@Test public void givenSimilarMapsWithArrayValue_whenCompareUsingGuavaEquivalence_thenSuccess() { Equivalence eq = new Equivalence() { @Override protected boolean doEquivalent(String[] a, String[] b) { return Arrays.equals(a, b); } @Override protected int doHash(String[] value) { return value.hashCode(); } }; MapDifference diff = Maps.difference(asiaCity1, asiaCity2, eq); assertTrue(diff.areEqual()); diff = Maps.difference(asiaCity1, asiaCity3, eq); assertFalse(diff.areEqual()); }

6. Заключение

В тази статия обсъдихме различни начини за сравняване на HashMaps в Java. Научихме множество начини да проверим дали две HashMaps са равни и как също да получим подробната разлика.

Пълният изходен код е достъпен в GitHub.