skip to content

compareTo & Ordering Contracts

compareTo defines natural ordering, and when it disagrees with equals the sorted collections behave surprisingly — TreeSet deduplicates by compareTo, not equals. The BigDecimal case is the classic example interviewers reach for.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is the Comparable interface in Java and what does its compareTo method return?

level: juniorimportance: must knowfreq 70%

answer

  1. One method: int compareTo(T)
  2. Sign matters, not magnitude: neg/zero/pos
  3. this < other => negative
  4. Defines the natural ordering
  5. Integer.compare, never a - b

basics

~10 s

Comparable defines a type's natural ordering through one method, compareTo. It returns a negative number if this object is smaller, zero if equal in order, and a positive number if larger.

solid answer

~40 s

Comparable<T> is a generic interface with a single method, int compareTo(T other), that defines a type's natural ordering. The return value is a sign, not a magnitude: negative means this comes before other, zero means they are equal in ordering, positive means this comes after. Implementing it lets a type be sorted by Collections.sort/Arrays.sort and used as a key in sorted structures like TreeSet and TreeMap without an explicit Comparator. Many standard types implement it: Integer, String (lexicographic), LocalDate (chronological), enums (declaration order). When ordering by multiple fields, compare them in priority order and return the first non-zero result. Prefer Integer.compare/Long.compare or Comparator.comparing chains over hand-written subtraction, which can overflow.

go deeper

for a junior

Knows Comparable has one method compareTo returning negative/zero/positive for less/equal/greater, and that implementing it enables sorting.

for a middle

Can implement multi-field compareTo correctly, uses Integer.compare/Comparator chains, and distinguishes Comparable from Comparator.

for a senior

Articulates the sign-not-magnitude rule, overflow pitfalls of subtraction, and which JDK types provide natural orderings and why.

for a principal

Frames natural ordering as an API design choice — when a type deserves one canonical order vs. forcing callers to supply a Comparator, and the maintenance cost of a baked-in ordering.

## What problem this solves Sorting and ordered storage need a way to ask: given two objects of the same type, which one comes first? Java expresses this through the **`Comparable`** interface, which defines a type's **natural ordering** — the single, default way instances of that type line up. ## The interface `java.lang.Comparable<T>` has exactly one method: ```java public interface Comparable<T> { int compareTo(T o); } ``` The `<T>` is a **generic type parameter** — a placeholder for the type being compared, filled in when you implement the interface (e.g. `class Money implements Comparable<Money>`). This makes the parameter type-safe: you write `compareTo(Money other)`, not `compareTo(Object other)`. ## What the return value means `compareTo` returns an **`int`**, but only its **sign** matters — not the magnitude: - **negative** (conventionally -1): `this` object is **less than** (comes before) `o`. - **zero**: `this` and `o` are **equal in ordering** (neither comes first). - **positive** (conventionally +1): `this` object is **greater than** (comes after) `o`. A mnemonic: `a.compareTo(b)` answers "`a` minus `b`" in spirit — positive if `a` is bigger. ## Who uses it Once a type implements `Comparable`, it works automatically with: - `Collections.sort(list)` and `Arrays.sort(array)` — sort by natural order. - `TreeSet<T>` and `TreeMap<T,?>` — keep elements/keys sorted; ordering by natural order. - `Collections.max`/`min`, `PriorityQueue`, binary search. Many JDK types already implement it: `Integer`/`Long`/`Double` (numeric), `String` (lexicographic, char-by-char), `LocalDate`/`Instant` (chronological), and **enums** (in declaration order via `ordinal`). ## Single field example ```java record Version(int major) implements Comparable<Version> { public int compareTo(Version other) { return Integer.compare(this.major, other.major); } } ``` `Integer.compare(a, b)` returns the correct sign **without overflow**. Writing `a - b` looks tempting but breaks when the subtraction overflows the `int` range (e.g. `Integer.MIN_VALUE - 1` wraps to a positive number), silently reversing the order. ## Multiple fields Compare fields in priority order; return at the first non-zero result: ```java int c = Integer.compare(this.year, o.year); if (c != 0) return c; return this.title.compareTo(o.title); ``` or, more readably, `Comparator.comparingInt(Version::major).thenComparing(...)` (a `Comparator` is the *external* sibling of `Comparable` — same sign convention, supplied separately instead of baked into the type). ## Comparable vs Comparator (one line) `Comparable` lives **on the type** and defines its one natural order; `Comparator` is a **separate object** you pass in to sort the same type many different ways. You will reach for `Comparator` whenever you need an ordering other than natural order, or for a type you can't modify.

  • Why prefer Integer.compare(a, b) over returning a - b?
    Subtraction can overflow the int range and wrap around to the wrong sign, silently corrupting the ordering. Integer.compare branches safely and always returns the correct sign.
  • What is the difference between Comparable and Comparator?
    Comparable is implemented by the type itself and defines its single natural ordering. Comparator is a separate object passed in, letting you order a type many ways or order types you cannot modify.

saying these in an interview costs you the question

  • Saying compareTo returns true/false or a boolean
  • Claiming the magnitude of the int is meaningful (it is not)
  • Using a - b subtraction (overflow risk) instead of Integer.compare
  • Confusing Comparable (on the type, natural order) with Comparator (external)

context

open as a page

What does it mean for compareTo to be consistent with equals, and when is it acceptable to break that consistency?

level: seniorimportance: must knowfreq 65%

basics

~10 s

Consistent means x.compareTo(y) == 0 exactly when x.equals(y) is true. It is strongly recommended but not required. Breaking it is allowed if documented, but it can make sorted collections behave surprisingly.

open as a page

How does a type's natural ordering relate to equality, and how do you choose between Comparable and Comparator?

level: middleimportance: should knowfreq 55%

basics

~20 s

Natural ordering is the single default order a type defines via Comparable. Ideally it matches equals. Use Comparable for the one canonical order; use a Comparator passed in when you need other orderings or can't change the type.

open as a page

What relational properties must a correct compareTo implementation satisfy, and what breaks if you violate them?

level: middleimportance: should knowfreq 50%

basics

~20 s

compareTo must impose a total order: it must be antisymmetric (if x is less than y then y is greater than x), transitive (if x < y and y < z then x < z), and reflexive (x compares 0 to itself). Violating these makes sorting and TreeMap behave unpredictably.

open as a page

Why might a TreeMap fail to find a key it actually contains, and how does this trace back to compareTo?

level: seniorimportance: should knowfreq 40%

basics

~20 s

TreeMap locates keys using compareTo, not equals or hashCode. If compareTo is inconsistent, unstable, or based on mutable fields that changed, the tree search takes a wrong path and get returns null even though the key is stored.

open as a page