Appearance
Lesson 05 · Comparison & Sorting
Objectives
After this lesson you will be able to:
- Implement
Comparable(natural order) andComparator(custom order). - Build comparators with
comparing,thenComparing,reversed, and null-handling. - Respect the
equals/hashCode/compareToconsistency contracts.
Comparable vs Comparator
Comparable<T>— a type's natural ordering, viaint compareTo(T o)on the class itself.Comparator<T>— an external, swappable ordering, viaint compare(T a, T b).
compareTo/compare return negative / zero / positive for less / equal / greater.
java
record Person(String name, int age) implements Comparable<Person> {
public int compareTo(Person o) { return Integer.compare(age, o.age); } // by age
}
list.sort(null); // natural order (Comparable)
list.sort(Comparator.comparing(Person::name)); // by name insteadExam trap
Don't compare with subtraction (a.age - b.age) — it overflows for large/negative values. Use Integer.compare(a, b). Collections.sort/List.sort need either Comparable elements or a Comparator, otherwise you get a ClassCastException (or it won't compile with a typed Comparator).
Building comparators
Comparator has fluent factories that chain:
java
Comparator<Person> byAgeThenName =
Comparator.comparingInt(Person::age)
.thenComparing(Person::name);
Comparator<Person> byNameDesc =
Comparator.comparing(Person::name).reversed();
Comparator<Person> nullsLast =
Comparator.comparing(Person::name, Comparator.nullsLast(Comparator.naturalOrder()));The consistency contracts
equals/hashCode: equal objects must have equal hash codes (Module 03).compareToconsistent withequals: ideallyx.compareTo(y) == 0iffx.equals(y).
Gotcha
A TreeSet/TreeMap decides equality by compareTo/compare returning 0, not equals. So a comparator that only compares one field treats two different-but-"equal-by-that-field" objects as duplicates — the second is dropped. Make the comparator a total order (add a tiebreaker) if you need all elements.
SDET note
When asserting sorted output, pin the order with an explicit, total Comparator (add a tiebreaker) so ties don't reorder between runs. For value objects, a record's generated equals plus a compareTo consistent with it keeps TreeSet/assertEquals behaving predictably.
Key Takeaways
Comparable= natural order (compareToon the type);Comparator= external order (compare). Both return negative/zero/positive.- Compare numbers with
Integer.compare, never subtraction (overflow). - Build comparators with
comparing/comparingInt/thenComparing/reversed/nullsLast. TreeSet/TreeMapusecompareTo/compare== 0 for equality — use a total order or lose "duplicates".
Lesson Quiz
Why avoid return a.age - b.age; in compareTo?
Comparable defines order via... and Comparator via...
How do you sort by age, then break ties by name?
A TreeSet uses a comparator that only compares the name field. Two people share a name. What happens?
What does list.sort(null) do for elements implementing Comparable?
Next: Module 05 Mini-Exam. Run the matching code in labs/src/main/java/com/jse21/m05_collections/.