liveBook · Manning

Equality contract

As explained in 100 Java Mistakes and How to Avoid Them

An equality contract is the set of behavioral requirements governing an equals implementation, including properties such as reflexivity, symmetry, transitivity, consistency, and null handling.

An equality contract defines how an `equals()` implementation must behave: an object compares consistently with itself and peers, handles `null`, and preserves symmetric and transitive results. Its paired `hashCode()` rule is essential: objects equal under `equals()` must return the same hash code. section 7.6 section 7.7

Malformed equality code can silently compare the wrong fields, dereference nullable fields, or make a value unequal to itself. A particularly easy typo is comparing one field with itself rather than with the corresponding field on the other object. Prefer generated `equals()` and `hashCode()`, use `Objects.equals()` for nullable fields, and regenerate both methods when participating fields change. section 7.6

Equal arrays, different hash buckets

Content-based `equals()` for array fields must be matched by content-based hashing. `Objects.hash(intData, stringData)` delegates to array `hashCode()`, which does not use array contents; two equal `DataHolder` values can therefore both remain in a `HashSet`. Hash the arrays with `Arrays.hashCode()` instead. section 7.7

var h1 = new DataHolder(new int[0], new String[0]);
var h2 = new DataHolder(new int[0], new String[0]);
System.out.println(h1.equals(h2));     #1
var set = new HashSet<>();
set.add(h1);
set.add(h2);
System.out.println(set.size());     #2

The listing creates two array-backed values that compare equal, then shows how an incompatible hash code prevents `HashSet` deduplication. section 7.7

Tests must check the contract directly rather than assume `assertNotEquals()` proves inequality. When equality is asymmetric or one argument is `null`, TestNG 7.4.0 `assertNotEquals()` can succeed without exposing the faulty direction. A dedicated verifier can test many contract conditions that are difficult to enumerate manually. section 10.6 section 7.6

How 100 Java Mistakes and How to Avoid Them covers it

How deep it goes
Explains implementation and testing pitfalls, including nullable fields and arrays, without deriving equality semantics formally.
Examples
Uses faulty field comparisons, nullable boxed data, array-backed DataHolder values, HashSet insertion, and a custom class whose equals() always returns true.
What you can do after
Diagnose/debug malformed equality and hashing implementations with generated methods, utility APIs, focused tests, and EqualsVerifier.
How it connects
Connects equals(), hashCode(), HashSet, HashMap, Objects.equals(), Objects.hash(), Arrays.hashCode(), and assertNotEquals().

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Java Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.