Comparable, Comparator, sorting

Collections · lesson 11 of 42 · 4 min read

Define one natural order and build any number of alternative orders on demand.

Open this lesson in the learning hub

Key points

  • Comparable lives on the class: one natural order. Comparator is a separate object, so you can have many.
  • Build comparators declaratively: Comparator.comparing(Employee::dept).thenComparing(Employee::name).
  • Flip direction with reversed(), or pass Comparator.reverseOrder() to a single key.
  • For int, long, double keys use comparingInt and friends — they avoid boxing.
  • Use Integer.compare(a, b), never a - b. Subtraction overflows and silently reverses your order.
  • List.sort is stable: equal elements keep their order. TreeSet treats compare-to-zero as a duplicate.

Example

import java.util.*;

public class Main {

    record Employee(String name, String dept, int salary) implements Comparable<Employee> {
        @Override public int compareTo(Employee other) {
            return Integer.compare(salary, other.salary);
        }
        @Override public String toString() { return name + "(" + dept + "," + salary + ")"; }
    }

    public static void main(String[] args) {
        List<Employee> staff = new ArrayList<>(List.of(
                new Employee("Ana", "eng", 120),
                new Employee("Bo",  "ops", 90),
                new Employee("Cy",  "eng", 90),
                new Employee("Di",  "ops", 120)));

        Collections.sort(staff);
        System.out.println("natural (salary)  : " + staff);

        staff.sort(Comparator.comparing(Employee::name));
        System.out.println("by name           : " + staff);

        staff.sort(Comparator.comparing(Employee::dept)
                             .thenComparing(Employee::salary, Comparator.reverseOrder())
                             .thenComparing(Employee::name));
        System.out.println("dept, salary desc : " + staff);

        System.out.println("max by salary     : " + Collections.max(staff));
        System.out.println("min by name       : " + Collections.min(staff, Comparator.comparing(Employee::name)));

        List<String> withNulls = new ArrayList<>(Arrays.asList("b", null, "a"));
        withNulls.sort(Comparator.nullsFirst(Comparator.naturalOrder()));
        System.out.println("nullsFirst        : " + withNulls);

        TreeSet<Employee> bySalary = new TreeSet<>(Comparator.comparingInt(Employee::salary));
        bySalary.addAll(staff);
        System.out.println("TreeSet by salary : " + bySalary + "   (90 and 120 'equal' -> deduped!)");
    }
}

One natural order via Comparable, every other order via Comparator.comparing chains.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.