Vergleich zweier HashMaps in Java

Zwei HashMaps in Java vergleichen

1. Überblick

In diesem Tutorial werdenwe’re going to explore different ways to compare two HashMaps in Java.

Wir werden mehrere Möglichkeiten diskutieren, um zu überprüfen, ob zweiHashMapsähnlich sind. Wir werden auch Java 8 Stream API und Guava verwenden, um die detaillierten Unterschiede zwischen verschiedenenHashMapszu ermitteln.

2. Verwenden vonMap.equals()

Zuerst verwenden wirMap.equals(), um zu überprüfen, ob zweiHashMaps dieselben Einträge haben:

@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));
}

Hier erstellen wir dreiHashMap-Objekte und fügen Einträge hinzu. Dann verwenden wirMap.equals(), um zu überprüfen, ob zweiHashMaps dieselben Einträge haben.

The way that Map.equals() works is by comparing keys and values using the Object.equals()method. Dies bedeutet, dass es nur funktioniert, wenn sowohl Schlüssel- als auch Wertobjekteequals() ordnungsgemäß implementieren.

Beispielsweise funktioniertMap.equals() nicht, wenn der Werttyp Array ist, da dieequals()-Methode eines Arrays die Identität und nicht den Inhalt des Arrays vergleicht:

@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. Verwenden der JavaStream-API

Wir können auch unsere eigene Methode implementieren, umHashMaps mit der Java 8Stream-API zu vergleichen:

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())));
}

Der Einfachheit halber haben wir die MethodeareEqual()implementiert, mit der wir jetzt die Objekte vonHashMap<String, String>vergleichen können:

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

Wir können aber auch unsere eigene MethodeareEqualWithArrayValue() anpassen, um Array-Werte zu verarbeiten, indem wirArrays.equals() verwenden, um zwei Arrays zu vergleichen:

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())));
}

Im Gegensatz zuMap.equals() vergleicht unsere eigene MethodeHashMaps erfolgreich mit Array-Werten:

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

4. Vergleichen vonHashMap Schlüsseln und Werten

Als nächstes wollen wir sehen, wie zweiHashMap-Schlüssel und ihre entsprechenden Werte verglichen werden.

4.1. Vergleichen vonHashMap Schlüsseln

Zuerst können wir überprüfen, ob zweiHashMapsdieselben Schlüssel haben, indem wir nur ihreKeySet()vergleichen:

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

4.2. Vergleichen derHashMap-Werte

Als Nächstes sehen wir, wie Sie die Werte vonHashMapeinzeln vergleichen.

Wir implementieren eine einfache Methode, um mithilfe derStream-API zu überprüfen, welche Schlüssel in beidenHashMaps denselben Wert haben:

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()))));
}

Wir können jetztareEqualKeyValues() verwenden, um zwei verschiedeneHashMaps zu vergleichen, um im Detail zu sehen, welche Schlüssel den gleichen Wert und welche unterschiedliche Werte haben:

@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. Kartenunterschied mit Guave

Schließlich sehen wirhow to get a detailed difference between two HashMaps using Guava Maps.difference().

Diese Methode gibt einMapDifference-Objekt zurück, das über eine Reihe nützlicher Methoden verfügt, um den Unterschied zwischenMaps. zu analysieren. Schauen wir uns einige davon an.

5.1. MapDifference.entriesDiffering()

Zuerst erhalten wircommon keys that have different values in each HashMap using 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());
}

Die MethodeentriesDiffering() gibt ein neuesMap zurück, das den Satz gemeinsamer Schlüssel undValueDifference Objekte als Wertesatz enthält.

Each ValueDifference object has a leftValue() and rightValue() methods that return the values in the two Maps.

5.2. MapDifference.entriesOnlyOnRight() undMapDifference.entriesOnlyOnLeft()

Dann können wir Einträge erhalten, die nur in einemHashMap existieren, indem wirMapDifference.entriesOnlyOnRight() undMapDifference.entriesOnlyOnLeft(): verwenden

@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()

Als nächsteswe’ll get common entries using 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. Anpassen des Verhaltens vonMaps.difference()

DaMaps.difference() standardmäßigequals() undhashCode() verwenden, um Einträge zu vergleichen, funktioniert dies nicht für Objekte, die sie nicht ordnungsgemäß implementieren:

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

Aberwe can customize the method used in comparison using Equivalence.

Zum Beispiel definieren wirEquivalence  für TypString[], umString[] Werte in unserenHashMaps nach Belieben zu vergleichen:

@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. Fazit

In diesem Artikel haben wir verschiedene Möglichkeiten diskutiert,HashMaps in Java zu vergleichen. Wir haben mehrere Möglichkeiten kennengelernt, um zu überprüfen, ob zweiHashMapsgleich sind und wie auch der detaillierte Unterschied ermittelt werden kann.

Der vollständige Quellcode ist verfügbarover on GitHub.