Comparator: a Swappable Ordering Strategy
Where you are: Week 0 review > Comparator
Try This First
A Book already has a natural order by author, set by compareTo. One screen needs books sorted by title instead. Decide whether to rewrite compareTo before reading on.
Reveal
Do not rewrite compareTo. Write a separate Comparator<Book> that orders by title, and pass it to the sort for that screen. The natural order stays; the alternate order is swapped in only where needed.
Before You Start
Check each box you can do from memory. A box you cannot check yet is not a problem; it points you to a quick refresher, not a grade.
Not sure? Take the 60-second self-check.
Try each from memory, then read the answer under it.
- What does
compareToreturn to signal order? A sign: negative ifthiscomes first, zero if tied, positive if it comes after. - How should you test that result for comes-before? With
< 0, never== -1, because any negative value means before.
What You Need To Walk In With
Walk into the next class able to state these:
Comparabledefines one natural order inside the class (compareTo(T other), one parameter, implicitly compared againstthis).Comparatordefines an alternate order outside the class (compare(T a, T b), two explicit parameters, nothis).- The same sign contract applies to both: negative means the first comes before the second.
- A
Comparatorcan be a named class or a lambda, and it can be swapped at each sort call without changing the class being sorted.
You should be able to: write a Comparator (named or lambda) and pass it to Arrays.sort.
How It Works
Comparable bakes in one order. For a second order, write a Comparator:
// Lambda form: order by title
Comparator<Book> byTitle = (a, b) -> a.getTitle().compareTo(b.getTitle());
// Named class form: order by author last name
public final class ByAuthorLastName implements Comparator<Book> {
@Override
public int compare(Book a, Book b) {
return a.getAuthor().getLastName().compareTo(b.getAuthor().getLastName());
}
}
Arrays.sort(books, byTitle);
Arrays.sort(books, new ByAuthorLastName());
The Comparator interface has one method, int compare(T a, T b). Both objects are explicit, neither is this. Swapping the comparator changes the order without touching the Book class at all.
| Comparable | Comparator | |
|---|---|---|
| Lives | inside the class | outside (or as a lambda) |
| Method | compareTo(T other) |
compare(T a, T b) |
| Parameters | one (compared with this) |
two, both explicit |
| Defines | the one natural order | one alternate order |
| Changing it | edits the class | swap at the sort call |
Worked Example: Predict, Then Check
Comparator<Book> byTitle = (a, b) -> a.getTitle().compareTo(b.getTitle());
// books: "Notes" (author Z), "Algorithms" (author A)
Arrays.sort(books, byTitle);
Predict which book is first after the sort.
Reveal
“Algorithms” is first. byTitle ignores the author and orders by title, and “Algorithms” comes before “Notes” alphabetically, even though the natural order (by author) would have put author A first for a different reason.
A Common Mistake
Treating Comparator and Comparable as the same thing leads to writing compare with one parameter or compareTo with two. compareTo(T other) takes one object and compares it with this; compare(T a, T b) takes two objects and compares them with each other. Match the method to the interface. (Source: BJP (Reges and Stepp), Ch 10.)
Go Deeper (optional)
For the curious: because a Comparator is just an object with one method, a lambda can stand in for it, and the modern API can build one for you, such as Comparator.comparing(Book::getTitle). Those builder forms, and chaining them with thenComparing, are the first topic in CSCD 211, which this lesson leads directly into.
Check Yourself
Close the notes and answer each one from memory, then reveal it. Pulling an idea back from memory is one of the strongest ways to make it stick.
Check your understanding
How does Comparator.compare differ from Comparable.compareTo?
You need a second sort order for a class that already has a natural order. What do you use?
Where does a Comparator live relative to the class it orders?
Sorting books by a byTitle Comparator: ‘Notes’ and ‘Algorithms’. Which is first?