Comparación de dos HashMaps en Java

1. Información general

En este tutorial, exploraremos diferentes formas de comparar dos HashMaps en Java .

Discutiremos varias formas de verificar si dos HashMaps son similares. También usaremos Java 8 Stream API y Guava para obtener las diferencias detalladas entre diferentes HashMaps .

2. Usando Map.equals ()

Primero, usaremos Map.equals () para verificar si dos HashMaps tienen las mismas entradas:

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

Aquí, estamos creando tres objetos HashMap y agregando entradas. Luego estamos usando Map.equals () para verificar si dos HashMaps tienen las mismas entradas.

La forma en que Map.equals () funciona es comparando claves y valores usando el método Object.equals () . Esto significa que solo funciona cuando los objetos clave y de valor implementan equals () correctamente.

Por ejemplo, Map.equals () no funciona cuando el tipo de valor es matriz, ya que el método equals () de una matriz compara la identidad y no el contenido de la matriz:

@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. Usando la API de Java Stream

También podemos implementar nuestro propio método para comparar HashMaps usando la API de 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()))); }

Para simplificar, implementamos el método areEqual () que ahora podemos usar para comparar objetos HashMap :

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

Pero también podemos personalizar nuestro propio método areEqualWithArrayValue () para manejar valores de matriz usando Arrays.equals () para comparar dos matrices:

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 diferencia de Map.equals () , nuestro propio método comparará con éxito HashMaps con valores de matriz:

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

4. Comparación de claves y valores de HashMap

A continuación, veamos cómo comparar dos claves HashMap y sus valores correspondientes.

4.1. Comparación de claves HashMap

Primero, podemos verificar si dos HashMaps tienen las mismas claves simplemente comparando su KeySet () :

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

4.2. Comparación de valores de HashMap

A continuación, veremos cómo comparar los valores de HashMap uno por uno.

Implementaremos un método simple para verificar qué claves tienen el mismo valor en ambos HashMaps usando 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())))); }

Ahora podemos usar areEqualKeyValues ​​() para comparar dos HashMaps diferentes para ver en detalle qué claves tienen el mismo valor y cuáles tienen valores diferentes:

@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. Mapear la diferencia usando guayaba

Finalmente, veremos cómo obtener una diferencia detallada entre dos HashMaps usando Guava Maps.difference ().

Este método devuelve un objeto MapDifference que tiene varios métodos útiles para analizar la diferencia entre los mapas. Echemos un vistazo a algunos de estos.

5.1. MapDifference.entriesDiffering ()

Primero, obtendremos claves comunes que tienen diferentes valores en cada HashMap usando 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()); }
    

El método entriesDiffering () devuelve un nuevo mapa que contiene el conjunto de claves comunes y objetos ValueDifference como el conjunto de valores.

Cada objeto ValueDifference tiene un método leftValue () y rightValue () que devuelven los valores en los dos mapas respectivamente.

5.2. MapDifference.entriesOnlyOnRight () y MapDifference.entriesOnlyOnLeft ()

Luego, podemos obtener entradas que existen en solo un HashMap usando MapDifference.entriesOnlyOnRight () y 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 ()

A continuación, obtendremos entradas comunes usando 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. Personalización del comportamiento de Maps.difference ()

Dado que Maps.difference () usa equals () y hashCode () de forma predeterminada para comparar entradas, no funcionará para objetos que no los implementen correctamente:

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

Pero, podemos personalizar el método utilizado en comparación usando Equivalencia .

Por ejemplo, definiremos Equivalencia para el tipo String [] para comparar los valores String [] en nuestros HashMaps como queramos :

@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. Conclusión

En este artículo, discutimos diferentes formas de comparar HashMaps en Java. Aprendimos varias formas de verificar si dos HashMaps son iguales y también cómo obtener la diferencia detallada.

El código fuente completo está disponible en GitHub.