How do you sort a list of objects by multiple fields using Comparator?

Comparator has factory and chaining methods since Java 8: Comparator.comparing() builds a comparator from a key, thenComparing() adds tie-breakers, and reversed(), nullsFirst() and nullsLast() adjust the order. Together they replace long compare() methods with one readable expression.

Key Points: • Comparator.comparing(Employee::department) sorts by one key. • .thenComparing(Employee::salary, Comparator.reverseOrder()) adds a second key in descending order. • comparingInt(), comparingLong() and comparingDouble() avoid boxing for primitive keys. • reversed() reverses the whole comparator built so far, so position it carefully. • Comparator.nullsLast(...) handles null values in a field without NullPointerException. • list.sort(comparator) sorts in place, and the sort is stable: equal elements keep their order.

Code Example:

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class MultiFieldSort {

    record Employee(String name, String department, int salary) {}

    public static void main(String[] args) {
        List<Employee> staff = new ArrayList<>(List.of(
                new Employee("Ravi", "QA", 70_000),
                new Employee("Asha", "DEV", 95_000),
                new Employee("Neha", "DEV", 95_000),
                new Employee("Karan", "DEV", 80_000),
                new Employee("Meera", "QA", 85_000)));

        // Department A-Z, then salary high-to-low, then name A-Z
        staff.sort(Comparator.comparing(Employee::department)
                .thenComparing(Employee::salary, Comparator.reverseOrder())
                .thenComparing(Employee::name));

        staff.forEach(e -> System.out.println(e.department() + "  " + e.salary() + "  " + e.name()));
    }
}

Output:

DEV 95000 Asha DEV 95000 Neha DEV 80000 Karan QA 85000 Meera QA 70000 Ravi

Good to Know: A classic mistake is adding .reversed() at the end of a long chain, which reverses every key, not just the last one. Passing Comparator.reverseOrder() to the specific thenComparing() call reverses only that field and keeps the intent clear.

Interview Tip: A concise interview answer is:

"I build the comparator with Comparator.comparing for the first field and chain thenComparing for each tie-breaker, passing Comparator.reverseOrder() for descending fields and using nullsLast when a field can be null. Then list.sort applies it in place, and because the sort is stable, equal elements keep their original order."

Previous question: What is the difference between List.of(), Collections.unmodifiableList() and Arrays.asList()?

Next question: What are the most useful methods of the Collections utility class?

More Java Collections interview questions

All Java Collections questions