Unravel › Java concepts › OOP and types
Comparable and Comparator
Sorting needs a rule for "which comes first".
Learn these first
At a glance
Comparable is "the class knows how to line itself up" (people by height); a Comparator is the teacher saying "line up by birthday today", a different rule each time without changing the people.
- 1compareTo(other) returns a negative number if this comes first, zero if equal, positive if this comes afterInteger, String and LocalDate already have one.
- 2Comparator.comparing(User::getName).thenComparing(User::getAge).reversed() builds a rule from small pieceslist.sort(cmp) and stream.sorted(cmp) use it.
- 3TreeMap, TreeSet and PriorityQueue use the natural order or the comparator you give them to decide order and, for sets and maps, also what counts as a duplicate
- The rule must be consistent: if a < b and b < c then a < c, and compare(a,b) must be the opposite sign of compare(b,a)
- Never compare numbers with subtraction (a - b): large values overflow and flip the sign
- List.sort and Arrays.sort for objects use TimSort (merge sort with run detection, O(n log n), stable)
import java.util.*;public class Person implements Comparable<Person> { final String name; final int age; Person(String name, int age) { this.name = name; this.age = age; } @Override public int compareTo(Person o) { return Integer.compare(age, o.age); } static void sortByName(List<Person> people) { people.sort(Comparator.comparing((Person p) -> p.name).thenComparing(p -> p.age).reversed()); }}- line 2 uses Comparable, the core of Comparable and Comparator
- line 5 uses compareTo, the core of Comparable and Comparator
- line 7 uses comparing, the core of Comparable and Comparator
Read the full explanation (about 1 min)
Sorting needs a rule for "which comes first". Comparable puts one natural rule inside the class (compareTo); a Comparator is a separate rule you can hand to a sort call.
A mental model
Comparable is "the class knows how to line itself up" (people by height); a Comparator is the teacher saying "line up by birthday today", a different rule each time without changing the people.
How it works
compareTo(other) returns a negative number if this comes first, zero if equal, positive if this comes after. Integer, String and LocalDate already have one.
Comparator.comparing(User::getName).thenComparing(User::getAge).reversed() builds a rule from small pieces. list.sort(cmp) and stream.sorted(cmp) use it.
TreeMap, TreeSet and PriorityQueue use the natural order or the comparator you give them to decide order and, for sets and maps, also what counts as a duplicate.
Going deeper
The rule must be consistent: if a < b and b < c then a < c, and compare(a,b) must be the opposite sign of compare(b,a). A broken rule gives "Comparison method violates its general contract" in TimSort.
Never compare numbers with subtraction (a - b): large values overflow and flip the sign. Use Integer.compare(a, b).
Keep compareTo consistent with equals where you can. A TreeSet treats "compares as 0" as duplicate even if equals says they differ.
Sorting is stable for objects (equal items keep their order), so you can sort twice: first by the minor key, then by the major key.
Under the hood
List.sort and Arrays.sort for objects use TimSort (merge sort with run detection, O(n log n), stable). Primitive arrays use a dual-pivot quicksort, which is not stable but does not need to be.
Common mistakes
- Subtracting integers in
compare, causing overflow bugs. - Forgetting null handling (
Comparator.nullsFirst). - Using
compareTothat disagrees withequalsin aTreeSetorTreeMap.
How Unravel recognises it
When you paste code, Unravel looks for these signs of comparable and comparator. Spotting them yourself is a good habit when you read unfamiliar code:
- Types:
Comparable - Method calls:
comparing()comparingInt()comparingDouble()comparingLong()thenComparing()reversed()compareTo()Comparator.naturalOrder()Comparator.reverseOrder()nullsFirst()nullsLast() - Method names you declare:
compareTo()compare()
Part of a learning path
- Modern Java syntax · previous: Wildcards and bounded generics
Related concepts
Frequently asked questions
What is Comparable and Comparator?
Sorting needs a rule for "which comes first". Comparable puts one natural rule inside the class (compareTo); a Comparator is a separate rule you can hand to a sort call.
What are the most common mistakes with Comparable and Comparator?
Subtracting integers in compare, causing overflow bugs. Forgetting null handling (Comparator.nullsFirst). Using compareTo that disagrees with equals in a TreeSet or TreeMap.
How can I see Comparable and Comparator in real code?
Paste your own Java into Unravel and it will point out where comparable and comparator appears, explain how it works at the detail level you choose, and draw the flow of the code around it.