# Comparing two maps

I have two maps declared as `Map<String, Object>`. The `Object` here could be another `Map<String, Object>` (and so on). I want to check if two maps are exactly the same without knowing their depth. Instead of using recursion can I compare the output of the `toString()` called on each map? Or is there a simpler way to compare the maps?

• may be this is dumb for others, yet it is important for you, so it becomes respectable and important at the end. Jul 17, 2014 at 22:38
• Using `toString()` would fail if the map entries came out in different orders, which is entirely possible. Jul 17, 2014 at 22:52
• @user3580294 If one map was a `TreeMap` and the other was a `HashMap` (included example in my answer :-) . Jul 17, 2014 at 23:18
• `.toString()` itself would have recursive behaviour. Why do you hate it?
– user824425
Jul 17, 2014 at 23:59
• @maythesource.com Yeah, realized the flaw with my comment really soon after I posted it, but for some reason didn't get a notification for your response... In any case, I initially thought that OP was talking about `HashMap` instances because my reading skills are terrible, but then realized that even for those what I said wasn't true. It was after that that I realized that OP just has `Map` instances. In any case, you are correct. Jul 18, 2014 at 5:03

You should use the `equals` method since this is implemented to perform the comparison you want. `toString()` itself uses an iterator just like `equals` but it is a more inefficient approach. Additionally, as @Teepeemm pointed out, `toString` is affected by order of elements (basically iterator return order) hence is not guaranteed to provide the same output for 2 different maps (especially if we compare two different maps).

Note/Warning: Your question and my answer assume that classes implementing the map interface respect expected `toString` and `equals` behavior. The default java classes do so, but a custom map class needs to be examined to verify expected behavior.

``````boolean equals(Object o)
``````

Compares the specified object with this map for equality. Returns true if the given object is also a map and the two maps represent the same mappings. More formally, two maps m1 and m2 represent the same mappings if m1.entrySet().equals(m2.entrySet()). This ensures that the equals method works properly across different implementations of the Map interface.

## Implementation in Java Source (java.util.AbstractMap)

Additionally, java itself takes care of iterating through all elements and making the comparison so you don't have to. Have a look at the implementation of `AbstractMap` which is used by classes such as `HashMap`:

`````` // Comparison and hashing

/**
* Compares the specified object with this map for equality.  Returns
* <tt>true</tt> if the given object is also a map and the two maps
* represent the same mappings.  More formally, two maps <tt>m1</tt> and
* <tt>m2</tt> represent the same mappings if
* <tt>m1.entrySet().equals(m2.entrySet())</tt>.  This ensures that the
* <tt>equals</tt> method works properly across different implementations
* of the <tt>Map</tt> interface.
*
* <p>This implementation first checks if the specified object is this map;
* if so it returns <tt>true</tt>.  Then, it checks if the specified
* object is a map whose size is identical to the size of this map; if
* not, it returns <tt>false</tt>.  If so, it iterates over this map's
* <tt>entrySet</tt> collection, and checks that the specified map
* contains each mapping that this map contains.  If the specified map
* fails to contain such a mapping, <tt>false</tt> is returned.  If the
* iteration completes, <tt>true</tt> is returned.
*
* @param o object to be compared for equality with this map
* @return <tt>true</tt> if the specified object is equal to this map
*/
public boolean equals(Object o) {
if (o == this)
return true;

if (!(o instanceof Map))
return false;
Map<K,V> m = (Map<K,V>) o;
if (m.size() != size())
return false;

try {
Iterator<Entry<K,V>> i = entrySet().iterator();
while (i.hasNext()) {
Entry<K,V> e = i.next();
K key = e.getKey();
V value = e.getValue();
if (value == null) {
if (!(m.get(key)==null && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
} catch (ClassCastException unused) {
return false;
} catch (NullPointerException unused) {
return false;
}

return true;
}
``````

## Comparing two different types of Maps

`toString` fails miserably when comparing a `TreeMap` and `HashMap` though `equals` does compare contents correctly.

Code:

``````public static void main(String args[]) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("2", "whatever2");
map.put("1", "whatever1");
TreeMap<String, Object> map2 = new TreeMap<String, Object>();
map2.put("2", "whatever2");
map2.put("1", "whatever1");

System.out.println("Are maps equal (using equals):" + map.equals(map2));
System.out.println("Are maps equal (using toString().equals()):"
+ map.toString().equals(map2.toString()));

System.out.println("Map1:"+map.toString());
System.out.println("Map2:"+map2.toString());
}
``````

Output:

``````Are maps equal (using equals):true
Are maps equal (using toString().equals()):false
Map1:{2=whatever2, 1=whatever1}
Map2:{1=whatever1, 2=whatever2}
``````
• does lambda expression make the condition better? Jul 17, 2014 at 22:40
• @Kick Buttowski What do you mean? Jul 17, 2014 at 22:42
• you said answering this question is complicated and since I try to learn Lambda experssion in Java, I was wondering to know if using lambda experssion would help? Jul 17, 2014 at 22:43
• @KickButtowski I am not on Java 8 yet but am sure if I flatten the map it becomes trivial :) Jul 17, 2014 at 22:45
• It should be emphasized that even if both maps have the same type, i.e. both are `HashMap`s, there is no guaranty that the iteration order will be the same, hence, comparing the `toString()` result will fail. The encountered order is an implementation detail that depends on the key’s hashcodes and the current capacity (which might differ, even if the size is the same), further, entries being stored in the same array element (aka having a hash collision) are linked in an order depending on the history of the map, i.e. insertion order or whether there were removals of other keys, etc. Nov 14, 2016 at 18:00

As long as you override `equals()` on each key and value contained in the map, then `m1.equals(m2)` should be reliable to check for maps equality.

The same result can be obtained also by comparing `toString()` of each map as you suggested, but using `equals()` is a more intuitive approach.

May not be your specific situation, but if you store arrays in the map, may be a little tricky, because they must be compared value by value, or using `Arrays.equals()`. More details about this see here.

# Comparing two Maps:

declare:

``````enum Activity{
REMOVED,
MODIFIED
}

@Data
@NoArgsConstructor
@AllArgsConstructor
static class FileStateRow {
String key;
String value;
Activity activity;
}

BiFunction<Map<String, Object>, Map<String, Object>, Map<String, FileStateRow>>
mapCompare = (newMap, oldMap) -> {
Map<String, FileStateRow> resMap = new HashMap<>();
newMap.forEach((k, v) -> {
if (!oldMap.containsKey(k)) {
System.out.println("newMap key:" + k + " is missing in oldMap - ADDED");
resMap.put(k, new FileStateRow(k, (String) v, Activity.ADDED));
} else {
if (oldMap.get(k) != null && !oldMap.get(k).equals(v)) {
System.out.println("newMap value change for key:" + k + ", old:" + oldMap.get(k) + ", new " + v);
resMap.put(k, new FileStateRow(k, (String) v, Activity.MODIFIED));
}
}
});

oldMap.forEach((k, v) -> {
if (!newMap.containsKey(k)) {
System.out.println("newMap key:" + k + " is missing in oldMap");
resMap.put(k, new FileStateRow(k, (String) v, Activity.REMOVED));
}
});
return resMap;
};
``````

use:

``````Map<String, Object> map1 = .. // initiate and put values in..
Map<String, Object> map2 = .. // initiate and put values in..

// compare...
Map<String, FileStateRow> res = mapCompare.apply(map1, map2);

// print results
res.forEach((k, v) -> {
System.out.println("key:" + k + ",  value " + v);
});
``````

by yl.
{"ft_lang_label":"__label__en","ft_lang_prob":0.7383644,"math_prob":0.90906256,"size":7633,"snap":"2023-40-2023-50","text_gpt3_token_len":1897,"char_repetition_ratio":0.11718443,"word_repetition_ratio":0.063094206,"special_character_ratio":0.2690947,"punctuation_ratio":0.1872116,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.96225476,"pos_list":[0],"im_url_duplicate_count":[null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-12-10T06:17:53Z\",\"WARC-Record-ID\":\"<urn:uuid:e1588179-ca50-4252-a229-e8b4a8cf0cc8>\",\"Content-Length\":\"209655\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:69696a5a-5e4d-4acf-8761-a5461692a4ca>\",\"WARC-Concurrent-To\":\"<urn:uuid:fab7ef7e-4d26-463c-a31b-99d207c8f958>\",\"WARC-IP-Address\":\"172.64.155.249\",\"WARC-Target-URI\":\"https://stackoverflow.com/questions/24814577/comparing-two-maps/24814634\",\"WARC-Payload-Digest\":\"sha1:7WP25MHVQJB2NVLB4WXCDOYHIQA7Q4JJ\",\"WARC-Block-Digest\":\"sha1:VFWYRPNNAFIKYWGCNZS3NWPZPFJUOD6V\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-50/CC-MAIN-2023-50_segments_1700679101282.74_warc_CC-MAIN-20231210060949-20231210090949-00299.warc.gz\"}"}