Objects.hash() is a convenient way to compute a hash code from object values, but it is not suitable for every equals() implementation. When equality treats two fields as interchangeable, Objects.hash(f1, f2) produces different results after the fields are swapped, violating the hashCode() contract. section 7.8
The unordered-fields trap
Suppose TwoFields considers (1, 2) equal to (2, 1). Objects.hash(1, 2) returns 994, while Objects.hash(2, 1) returns 1,024. Use a symmetric calculation such as f1 + f2, or normalize the fields during construction so generated equals() and hashCode() remain valid. section 7.8
Choose the implementation according to the equality rule:
- Use Objects.hash() when the fields have ordinary order-sensitive equality. section 7.8
- Do not use Objects.hash(f1, f2) when equals() treats f1 and f2 as interchangeable; use a symmetric hash instead. section 7.8
- Prefer IDE-generated equals() and hashCode(), or normalize immutable objects on construction when that restores ordinary field equality. section 7.8 section 2.1.1
class TwoFields {
int f1, f2;
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
TwoFields twoFields = (TwoFields) o;
return f1 == twoFields.f1 && f2 == twoFields.f2 ||
f1 == twoFields.f2 && f2 == twoFields.f1;
}
}
Inspect the unordered equality rule that makes a direct Objects.hash(f1, f2) implementation unsafe. section 7.8
public int hashCode() {
return f1 + f2;
}
Compare a symmetric addition-based hash with the order-sensitive result from Objects.hash(). section 7.8
