Value-based classes are types that are defined solely by their internal state and whose identity cannot be guaranteed at runtime. According to the documentation, a value-based class:
- does not provide any instance creation mechanism that promises a unique identity on each method call — in particular, any factory method’s contract must allow for the possibility that if two independently-produced instances are equal according to
equals(), they may also be equal according to==;- the class’s methods treat instances as freely substitutable when equal, meaning that interchanging any two instances x and y that are equal according to
equals()produces no visible change in the behavior of the class’s methods.
As such, instances of value-based classes should never be used with identity-sensitive operations, including reference equality (==)
or identity hashing (System.identityHashCode()).
This rule raises an issue when an identity-sensitive operation is applied on a known value-based class. That includes:
java.lang package, such as Integer, Boolean or
Double;Optional, OptionalDouble, OptionalLong, OptionalInt;java.time package and its sub-packages, except Clock.== may return false for two objects representing the exact same value, or it may return true for
two objects that were instantiated by different calls to the same factory method, with the same arguments.System.identityHashCode() on two instances representing the exact same information may return different values.Use .equals() to compare instances of value-based classes for equality, and .hashCode() to compute their hashes.
Instant start = Instant.now();
Instant end = Instant.now();
if (start == end) { // Noncompliant: Comparing memory addresses, not temporal values.
// ...
}
Optional<Integer> opt = Optional.of(1);
int hash = System.identityHashCode(opt); // Noncompliant
Instant start = Instant.now();
Instant end = Instant.now();
if (start.equals(end)) { // Compliant: Comparing semantic values for equality.
// ...
}
Optional<Integer> opt = Optional.of(1);
int hash = opt.hashCode(); // Compliant