55. Taking on the hard way to discover equals()
Check out the following code:
Integer x1 = 14; Integer y1 = 14;
Integer x2 = 129; Integer y2 = 129;
List<Integer> listOfInt1 = new ArrayList<>(
Arrays.asList(x1, y1, x2, y2));
listOfInt1.removeIf(t -> t == x1 || t == x2);
List<Integer> listOfInt2 = new ArrayList<>(
Arrays.asList(x1, y1, x2, y2));
listOfInt2.removeIf(t -> t.equals(x1) || t.equals(x2));
So, initially, listOfInt1
and listOfInt2
have the same items, [x1
=14, y1
=14, x2
=129, y2
=129]. But, what will contain listOfInt1
/listOfInt2
after executing the code based on removeIf()
and ==
, respectively equals()
?
The first list will remain with a single item, [129]. When t
is x1
, we know that x1 == x1
, so 14 is removed. But, why is x2
removed? When t
is y1
, we know that y1 == x1
should be false
since, via ==
, we compare the object’s references in memory, not their values. Obviously, y1
and x1
should have different references in the memory… or shouldn’t they ? Actually, Java has an internal rule to cache integers in -127 … 128. Since x1
=14 is cached, y1
=14 uses the cache so no new Integer
is created. This is why y1 == x1
and y1
is removed as well. Next, t
is x2
, and x2 == x2
, so x2
is removed. Finally, t
is y2
, but y2 == x2
returns false
, since 129 > 128 is not cached, so x2
and y2
have different references in memory.
On the other hand, when we use equals()
, which is the recommended approach for comparing the object’s values, the resulting list is empty. When t
is x1
, x1
=x1
, so 14 is removed. When t
is y1
, y1
=x1
, so y1
is removed as well. Next, t
is x2
, and x2
= x2
, so x2
is removed. Finally, t
is y2
, and y2
=x2
, so y2
is removed as well.