Stage 5: Collections compared, lesson 6 of 8

Comparable vs Comparator

Intermediate3 min read@since 8Code runs on your Java 25
Explain it forThe essentials plus production detail and pitfalls.

Both define how to order objects. The difference is where the ordering lives and how many you can have:

  • Comparable: the class orders itself by implementing Comparable<T> and its compareTo(T other) method. That's the object's natural order, and there's only one. Collections.sort(list), TreeSet and TreeMap use it by default. String, Integer and LocalDate are Comparable.
  • Comparator: a separate object with a compare(a, b) method. You can have as many as you like, and you can sort classes you can't modify. Since Java 8 you rarely write one by hand: Comparator.comparing, thenComparing, reversed, nullsFirst and comparingInt build them for you.

Rule of thumb: give a class a Comparable natural order only if there's one obvious way to order it (by id, by date). Use Comparators for everything else, such as the different sort options on a web page.

Side by side

ComparableComparator
Packagejava.langjava.util
MethodcompareTo(T other)compare(T a, T b)
DefinedInside the class being sortedOutside, as a separate object or lambda
How many ordersOne (the natural order)As many as you need
Need to change the class?YesNo: works for any class
Java 8 helpersNonecomparing, thenComparing, reversed, nullsFirst
Used byCollections.sort(list), TreeSet, TreeMap by defaultlist.sort(cmp), new TreeSet<>(cmp), stream.sorted(cmp)

Example

Java
record Employee(int id, String name, double salary) implements Comparable<Employee> {
    @Override public int compareTo(Employee other) {
        return Integer.compare(id, other.id);          // natural order: by id
    }
}

List<Employee> staff = new ArrayList<>(List.of(
        new Employee(3, "Ravi", 90_000), new Employee(1, "Asha", 120_000), new Employee(2, "Meera", 90_000)));

Collections.sort(staff);                                // by id (Comparable)

staff.sort(Comparator.comparingDouble(Employee::salary).reversed()
        .thenComparing(Employee::name));                // salary high to low, then name (Comparator)

Common mistake

Implementing compareTo with subtraction. It works in tests with small numbers and fails in production with large ones.

Under the hood

Never compare with subtraction (return a.age - b.age): it overflows for large values and gives wrong orders. Use Integer.compare or Comparator.comparingInt. Keep natural orders consistent with equals() (compareTo returns 0 exactly when equals is true), or sorted sets and maps will treat unequal objects as duplicates. The lesson "Sorting objects" covers more comparator techniques.

Check yourself

Which interface would you use to sort a class from a library you can't change?

How this connects

Where this leads

You've reached the end of this thread. Try a learning path for what's next.

Part of Java 8 and collections, practically.

Was this lesson helpful?

Finished reading? Mark it complete to track your progress.