Confronto di due HashMap in Java

1. Panoramica

In questo tutorial, esploreremo diversi modi per confrontare due HashMap in Java .

Discuteremo diversi modi per verificare se due HashMap sono simili. Useremo anche Java 8 Stream API e Guava per ottenere le differenze dettagliate tra i diversi HashMap .

2. Utilizzo di Map.equals ()

Innanzitutto, useremo Map.equals () per verificare se due HashMap hanno le stesse voci:

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

Qui stiamo creando tre oggetti HashMap e aggiungendo voci. Quindi stiamo usando Map.equals () per verificare se due HashMap hanno le stesse voci.

Il modo in cui funziona Map.equals () è confrontando chiavi e valori utilizzando il metodo Object.equals () . Ciò significa che funziona solo quando entrambi gli oggetti chiave e valore implementano correttamente equals () .

Ad esempio, Map.equals () non funziona quando il tipo di valore è array, poiché il metodo equals () di un array confronta l'identità e non il contenuto dell'array:

@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. Utilizzo dell'API Java Stream

Possiamo anche implementare il nostro metodo per confrontare HashMaps utilizzando l' API Java 8 Stream :

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

Per semplicità, abbiamo implementato il metodo areEqual () che ora possiamo utilizzare per confrontare gli oggetti HashMap :

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

Ma possiamo anche personalizzare il nostro metodo areEqualWithArrayValue () per gestire i valori degli array utilizzando Arrays.equals () per confrontare due array:

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

A differenza di Map.equals () , il nostro metodo confronterà con successo HashMaps con i valori dell'array:

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

4. Confronto di chiavi e valori HashMap

Successivamente, vediamo come confrontare due chiavi HashMap e i loro valori corrispondenti.

4.1. Confronto delle chiavi HashMap

Innanzitutto, possiamo verificare se due HashMap hanno le stesse chiavi semplicemente confrontando il loro KeySet () :

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

4.2. Confronto dei valori di HashMap

Successivamente, vedremo come confrontare i valori di HashMap uno per uno.

Implementeremo un metodo semplice per verificare quali chiavi hanno lo stesso valore in entrambe le HashMap utilizzando l' API Stream :

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

Ora possiamo usare areEqualKeyValues ​​() per confrontare due diverse HashMap per vedere in dettaglio quali chiavi hanno lo stesso valore e quali hanno valori diversi:

@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. Differenza mappa utilizzando Guava

Infine, vedremo come ottenere una differenza dettagliata tra due HashMap utilizzando Guava Maps.difference ().

Questo metodo restituisce un oggetto MapDifference che dispone di numerosi metodi utili per analizzare la differenza tra le mappe. Diamo un'occhiata ad alcuni di questi.

5.1. MapDifference.entriesDiffering ()

Innanzitutto, otterremo chiavi comuni che hanno valori diversi in ogni HashMap utilizzando 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()); }
    

Il metodo entryDiffering () restituisce una nuova mappa che contiene l'insieme di chiavi comuni e oggetti ValueDifference come insieme di valori.

Ogni oggetto ValueDifference ha un metodo leftValue () e rightValue () che restituiscono rispettivamente i valori nelle due mappe .

5.2. MapDifference.entriesOnlyOnRight () e MapDifference.entriesOnlyOnLeft ()

Quindi, possiamo ottenere voci che esistono in una sola HashMap utilizzando MapDifference.entriesOnlyOnRight () e 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 ()

Successivamente, otterremo voci comuni utilizzando 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. Personalizzazione del comportamento di Maps.difference ()

Since Maps.difference() use equals() and hashCode() by default to compare entries, it won't work for Objects that don't implement them properly:

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

But, we can customize the method used in comparison using Equivalence.

For example, we'll define Equivalence for type String[] to compare String[] values in our HashMaps as we like:

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

In this article, we discussed different ways to compare HashMaps in Java. We learned multiple ways to check if two HashMaps are equal and how to get the detailed difference as well.

The full source code is available over on GitHub.