Card 07/ 09

GotchaDifficulty: Advanced1 min

Comparator Contract Violations: "Comparison Method Violates Its General Contract"

A sort that always worked throws on one particular list, because the comparator is inconsistent.

Java's sort assumes the comparator is consistent: if it says a before b and b before c, then a before c, and so on. When the sort catches a comparator breaking those rules, it throws IllegalArgumentException with the message "Comparison method violates its general contract!".

A sort that has always worked throws on a particular list. The same comparator on a shorter list is fine:

text
Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
What a comparator has to guarantee
RuleMeans
AntisymmetryIf compare(a, b) is negative, compare(b, a) is positive
TransitivityIf a is before b and b is before c, then a is before c
Consistent tiesIf a and b tie, they compare the same way against every c

The two usual causes are the overflow from subtracting, and a comparator that returns zero for pairs it cannot decide between while ordering them differently by some other route. Both break transitivity, and neither shows until the sort happens to compare the offending three elements.

Build comparators from Comparator.comparing and thenComparing rather than writing the arithmetic. Those are consistent by construction, so the contract stops being something you have to remember.