JDK-8196069 : Misleading documentation of Objects.equals
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 8,9,10
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • Submitted: 2018-01-23
  • Updated: 2019-06-05
  • Resolved: 2019-06-05
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
sun-jdk-1.8.0_51

ADDITIONAL OS VERSION INFORMATION :
Not relevant

A DESCRIPTION OF THE PROBLEM :
The documentation of Objects.equals states:

"""
Returns true if the arguments are equal to each other and false otherwise. Consequently, if both arguments are null, true is returned and if exactly one argument is null, false is returned. Otherwise, equality is determined by using the equals method of the first argument.
"""

However, it is possible to construct a pathological case which violates this: a class which overrides equals(Object) to return false will return "true" for Objects.equals(a, a), despite a.equals(a) being false.

If a is non-null, then the documentation suggests that you will hit the "Otherwise" case, meaning that a.equals(a) will be invoked, so it should be false. However, it is caught by the "a == a" in the conditional expression, so true is returned.

The documentation should be clarified to reflect this. For example:

"""
if both arguments are null **or refer to the same instance**, true is returned
"""

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
https://ideone.com/f2qBhR

import java.util.Objects;

class Ideone
{
	@Override public boolean equals(Object other) {
		return false;
	}

	public static void main (String[] args) throws java.lang.Exception
	{
		Ideone i = new Ideone();
		System.out.println(i == null);
		System.out.println(i.equals(i));
		System.out.println(Objects.equals(i, i));
	}
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
false
false
false
ACTUAL -
false
false
true

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
https://ideone.com/f2qBhR

import java.util.Objects;

class Ideone
{
	@Override public boolean equals(Object other) {
		return false;
	}

	public static void main (String[] args) throws java.lang.Exception
	{
		Ideone i = new Ideone();
		System.out.println(i == null);
		System.out.println(i.equals(i));
		System.out.println(Objects.equals(i, i));
	}
}
---------- END SOURCE ----------


Comments
Doc was updated by JDK-8223112 for similar reasons. Closing as a duplicate.
05-06-2019

In the example, the equals method violates the reflexive property - "for any non-null reference value x, x.equals(x) should return true." This pretty much means all bets are off. This is similar to the wide variety of breakage that can occur if objects are stored in a Set and its equals() and hashCode() methods are inconsistent. Consider this other pathological case: class X { public boolean equals(Object o) { return o == null || this == o; } } X x = new X(); Objects.equals(x, null); // true! This also appears to violate the spec of Objects.equals(). It's not actually clear to me whether it's worthwhile to update the spec for Objects.equals().
05-06-2019