How to Check if HashMaps are Equal in Java


What is the simplest way to check if two hashmaps are equal in Java?

Compare HashMaps with Map.equals()

We can easily use Map.equals() to compare HashMaps.

boolean areMapsEqual(HashMap<String, String> m1, HashMap<String, String> m2) {
  return m1.equals(m2);
}

Map.equals() works by comparing each key and value using Object.equals(), which implies that both the keys and values need to properly implement the equals() method.

For instance, this would not work if the values were arrays, since the arr1.equals(arr2) would compare the reference of the two arrays rather than the contents of the array.

Compare HashMaps with the Stream API

Instead of using Map.equals(), we can iterate through each key-value pair in the first map and compare it to the second map.

boolean areMapsEqual(HashMap<String, String> m1, HashMap<String, String> m2) {
  if (m1.size() != m2.size()) { return false; }
  return m1.entrySet().stream()
    .allMatch(e -> e.getValue().equals(m2.get(e.getKey())));
}

Note that we’re using Object.equals() instead of Map.equals() in this approach to compare the values in each entry.

This approach is more flexible since we can use Arrays.equals() to fix the problem we had in the first approach. If we know we’re working with values of type String[] for instance, we can modify this method.

boolean areMapsEqual(HashMap<String, String[]> m1, HashMap<String, String[]> m2) {
  if (m1.size() != m2.size()) { return false; }
  return m1.entrySet().stream()
    .allMatch(e -> Arrays.equals(e.getValue(), m2.get(e.getKey())));
}

Compare HashMaps with Maps.Difference()

Another way to compare HashMaps is using Guava’s MapDifference.

We can pass both maps into Maps.difference() and easily get the differing keys and values.

Let’s check out how we can compare the HashMaps and log useful information if the maps are not equal.

boolean areMapsEqual(HashMap<String, String> m1, HashMap<String, String> m2) {
  MapDifference<String, String> diff = Maps.difference(m1, m2);
  if (diff.areEqual()) { return true; }
  Map<String, String> onlyLeft = diff.entriesOnlyOnLeft();
  Map<String, String> onlyRight = diff.entriesOnlyOnRight();
  Map<String, String> inBoth = diff.entriesInCommon();
  LOG.error(
    "Shared keys rows with different counts (size={}): {}",
    diff.entriesDiffering().size(),
    diff.entriesDiffering()
  );
  LOG.error("Entries only in m1 (size={}): {}", onlyLeft.size(), onlyLeft);
  LOG.error("Entries only in m2 (size={}): {}", onlyRight.size(), onlyRight);
  LOG.error("Entries in both m1/m2 (size={}): {}", inBoth.size(), inBoth);
  return false;
}

All that being said, we still run into the same problem as with the first approach.

This method uses Object.equals() to compare values. So, how would we compare values of type String[]?

We can define an Equivalence for our array type, and then pass that into MapDifference.

boolean areMapsEqual(HashMap<String, String[]> m1, HashMap<String, String[]> m2) {
  Equivalence<String[]> eq = new Equivalence<String[]>() {
    @Override
    protected boolean doEquivalent(String[] a, String[] b) {
      return Arrays.equals(a, b);
    }
    @Override
    protected int doHash(String[] value) {
      return value.hashCode();
    }
  };
  MapDifference<String, String[]> diff = Maps.difference(m1, m2, eq);
  if (diff.areEqual()) { return true; }
  Map<String, String[]> onlyLeft = diff.entriesOnlyOnLeft();
  Map<String, String[]> onlyRight = diff.entriesOnlyOnRight();
  Map<String, String[]> inBoth = diff.entriesInCommon();
  LOG.error(
    "Shared keys rows with different counts (size={}): {}",
    diff.entriesDiffering().size(),
    diff.entriesDiffering()
  );
  LOG.error("Entries only in m1 (size={}): {}", onlyLeft.size(), onlyLeft);
  LOG.error("Entries only in m2 (size={}): {}", onlyRight.size(), onlyRight);
  LOG.error("Entries in both m1/m2 (size={}): {}", inBoth.size(), inBoth);
  return false;
}