I have two Map objects: one HashMap
and one LinkedHashMap
. Both contain the same values (e.g., [1, 2]), and for the LinkedHashMap
, the insertion order is preserved. However, when I compare the collections returned by the values() function of these maps using the equals() method, the comparison returns false.
I initially assumed this might be due to HashMap
not preserving insertion order. But when I perform the same comparison with two LinkedHashMap
objects, where the insertion order is indeed preserved, the equals()
method still returns false.
Can someone explain why the equals()
method returns false in both cases, even though:
LinkedHashMap
?import java.util.LinkedHashMap;
import java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
// HashMap example
Map<String, Integer> map1 = new HashMap<>();
map1.put("a", 1);
map1.put("b", 2);
Map<String, Integer> map2 = new HashMap<>();
map2.put("x", 1);
map2.put("y", 2);
System.out.println("map1 values: " + map1.values()); // prints [1, 2]
System.out.println("map2 values: " + map2.values()); // prints [1, 2]
System.out.println("map1.values().equals(map2.values()): " + map1.values().equals(map2.values())); // returns false
// LinkedHashMap example
Map<String, Integer> map1l = new LinkedHashMap<>();
map1l.put("a", 1);
map1l.put("b", 2);
Map<String, Integer> map2l = new LinkedHashMap<>();
map2l.put("x", 1);
map2l.put("y", 2);
System.out.println("map1l values: " + map1l.values()); // prints [1, 2]
System.out.println("map2l values: " + map2l.values()); // prints [1, 2]
System.out.println("map1l.values().equals(map2l.values()): " + map1l.values().equals(map2l.values())); // still returns false
}
}
The reason why the collections returned by the two instances of HashMap
are considered not equal, even though they contain the same elements in the same order, is because the actual implementation of Collection
returned by HashMap.values()
is an inner class of HashMap
called Values
, which doesn't provide a proper definition of the equals()
method.
HashMap$Values
inherits the definition of its equals()
method from the Object
class, which only compares the memory address of the current object with the given argument. Hence, since the method compares two different objects residing in two different memory addresses, the method returns false
.
The same thing also happens when you're comparing the collections returned by your LinkedHashMap
instances. In this case though, you're comparing two instances of LinkedHashMap$LinkedValues
that don't provide a proper definition of equals()
as well, inheriting its definition from Object
.
If you need to compare the values returned by a Map
implementation, you could pass the collection returned by values()
to the conversion constructor of:
ArrayList
if duplicate elements are allowed and order matters.HashSet
if elements must be unique and order is not relevant.Also, make sure that the values' class provides a proper definition of equals()
and hasCode()
according to the general contract of hashcode, since the definitions of equals()
offered by ArrayList
and HashSet
are based on the equals()
of their elements.
//Comparing the LinkedHashMap values via ArrayList
List<Integer> list1 = new ArrayList<>(map1l.values());
List<Integer> list2 = new ArrayList<>(map2l.values());
System.out.println(list1.equals(list2)); //true
//Comparing the LinkedHashMap values via HashSet
Set<Integer> set1 = new HashSet<>(map1l.values());
Set<Integer> set2 = new HashSet<>(map2l.values());
System.out.println(set1.equals(set2)); //true