Comparable<T> and Comparator<T> both define orderings, but they live in different places and serve different roles. Comparable is the natural ordering baked into a type; Comparator is an external strategy for ordering you can swap, compose, and reverse.
The split at a glance
Comparable<T>— single methodint compareTo(T other). Implemented by the type itself. Returned byTreeMap/TreeSet/Collections.sortwhen no comparator is supplied. Examples:Integer,String,BigDecimal,LocalDate.Comparator<T>— single methodint compare(T a, T b). Passed to sorting code. Stateless or stateful. Composable viathenComparing,reversed,nullsFirst.
When to use which
- Is there one obvious correct ordering for the type? Implement
Comparable. Numeric types, dates, identifiers all have one. - Is the ordering context-dependent (sort by name, then by date, then descending by price)? Use
Comparator. Multiple comparators can coexist for the same type. - Are you a library author? Implement
Comparablefor natural ordering AND let callers pass aComparatorfor overrides — sorted collections accept both.
The compareTo / compare contract
Both methods return a negative int if a < b, zero if a == b (per the comparator), positive int if a > b. Implementations must be:
- Antisymmetric —
sgn(compare(a, b)) == -sgn(compare(b, a)). - Transitive —
a > bandb > cimpliesa > c. - Consistent with itself across calls.
There's a fourth highly-recommended (but not strictly required) property: consistent with equals — compare(a, b) == 0 if and only if a.equals(b). Violating this leads to weirdness in TreeSet (covered in the next question).
What you'll cover
ComparablevsComparatormechanics and trade-offs.- Why
BigDecimalfamously breaks the consistent-with-equals recommendation. - Composing comparators with
comparing,thenComparing,reversed. nullsFirstandnullsLastfor null-tolerant ordering.- Why
HashSetrequires neither butTreeSetrequires one.