Comparaison de deux HashMaps en Java

Comparer deux HashMaps en Java

1. Vue d'ensemble

Dans ce didacticiel,we’re going to explore different ways to compare two HashMaps in Java.

Nous allons discuter de plusieurs façons de vérifier si deuxHashMapsont similaires. Nous utiliserons également l'API Java 8 Stream et Guava pour obtenir les différences détaillées entre les différentsHashMaps.

2. Utilisation deMap.equals()

Premièrement, nous allons utiliserMap.equals() pour vérifier si deuxHashMaps ont les mêmes entrées:

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

Ici, nous créons trois objetsHashMapet ajoutons des entrées. Ensuite, nous utilisonsMap.equals() pour vérifier si deuxHashMaps ont les mêmes entrées.

The way that Map.equals() works is by comparing keys and values using the Object.equals()method. Cela signifie qu'il ne fonctionne que lorsque les objets clé et valeur implémentent correctementequals().

Par exemple,Map.equals() ne fonctionne pas lorsque le type de valeur est tableau, car la méthodeequals() d'un tableau compare l'identité et non le contenu du tableau:

@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. Utilisation de l'API JavaStream

Nous pouvons également implémenter notre propre méthode pour comparerHashMaps en utilisant l'API Java 8Stream:

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

Pour simplifier, nous avons implémenté la méthodeareEqual() que nous pouvons désormais utiliser pour comparer les objetsHashMap<String, String>:

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

Mais nous pouvons également personnaliser notre propre méthodeareEqualWithArrayValue() pour gérer les valeurs de tableau en utilisantArrays.equals() pour comparer deux tableaux:

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

Contrairement àMap.equals(), notre propre méthode comparera avec succèsHashMaps avec les valeurs du tableau:

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

4. Comparaison des clés et des valeursHashMap

Voyons ensuite comment comparer deux clésHashMap et leurs valeurs correspondantes.

4.1. Comparaison des clésHashMap

Tout d'abord, nous pouvons vérifier si deuxHashMaps ont les mêmes clés en comparant simplement leursKeySet():

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

4.2. Comparaison des valeursHashMap

Ensuite, nous verrons comment comparer les valeurs deHashMap une par une.

Nous allons mettre en œuvre une méthode simple pour vérifier quelles clés ont la même valeur dans les deuxHashMaps à l'aide de l'APIStream:

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

Nous pouvons maintenant utiliserareEqualKeyValues() pour comparer deuxHashMaps différents pour voir en détail quelles clés ont la même valeur et lesquelles ont des valeurs différentes:

@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. Différence de carte en utilisant la goyave

Enfin, nous verronshow to get a detailed difference between two HashMaps using Guava Maps.difference().

Cette méthode retourne un objetMapDifference qui a un certain nombre de méthodes utiles pour analyser la différence entre lesMaps. Examinons quelques-unes de celles-ci.

5.1. MapDifference.entriesDiffering()

Premièrement, nous obtiendronscommon 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());
}

La méthodeentriesDiffering() renvoie un nouveauMap qui contient l'ensemble de clés communes et les objetsValueDifference comme ensemble de valeurs.

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

5.2. MapDifference.entriesOnlyOnRight() etMapDifference.entriesOnlyOnLeft()

Ensuite, nous pouvons obtenir des entrées qui n'existent que dans un seulHashMap en utilisantMapDifference.entriesOnlyOnRight() etMapDifference.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()

Ensuite,we’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. Personnalisation du comportement deMaps.difference()

CommeMaps.difference() utiliseequals() ethashCode() par défaut pour comparer les entrées, cela ne fonctionnera pas pour les objets qui ne les implémentent pas correctement:

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

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

Par exemple, nous allons définirEquivalence  pour le typeString[] pour comparer les valeurs deString[] dans nosHashMaps comme nous le souhaitons:

@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

Dans cet article, nous avons discuté de différentes façons de comparer lesHashMaps en Java. Nous avons appris plusieurs façons de vérifier si deuxHashMaps sont égaux et comment obtenir la différence détaillée.

Le code source complet est disponibleover on GitHub.