Java ProgramsCollectionsCustom Comparator

Custom Comparator in Java

intermediate·  Collections  ·  Comparator & Comparable

Problem

A single-field Comparator can be chained with thenComparing() to add a tiebreaker field, without writing a manual multi-step comparison by hand.

Given a list of Person objects, sort them by last name, and break any ties using first name.

Input
Bob Smith, Alice Smith, Charlie Jones, sorted by last name then first name
Output
Jones: Charlie Smith: Alice Smith: Bob

Java Program

Java
import java.util.ArrayList; import java.util.Comparator; import java.util.List; class Person { String firstName; String lastName; Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } } public class CustomComparatorDemo { public static void main(String[] args) { List<Person> people = new ArrayList<>(); people.add(new Person("Bob", "Smith")); people.add(new Person("Alice", "Smith")); people.add(new Person("Charlie", "Jones")); Comparator<Person> byLastThenFirst = Comparator .comparing((Person p) -> p.lastName) .thenComparing(p -> p.firstName); // tiebreaker, only used when last names match people.sort(byLastThenFirst); for (Person p : people) { System.out.println(p.lastName + ": " + p.firstName); } } }

Output

Jones: Charlie Smith: Alice Smith: Bob

Core Logic

Building the primary ordering with comparing(), then chaining thenComparing() for the tiebreaker field, composes two separate comparison rules into one Comparator without any manual if/else logic.

How It Works
  1. 1Comparator.comparing((Person p) -> p.lastName) builds a Comparator that orders purely by last name.
  2. 2.thenComparing(p -> p.firstName) chains a second rule that only gets consulted when two people share the same last name.
  3. 3people.sort(byLastThenFirst) applies the combined Comparator to the whole list in one call.
  4. 4The two Smiths — Alice and Bob — share a last name, so thenComparing()'s first-name rule is what decides their relative order.
Sorting [Bob Smith, Alice Smith, Charlie Jones] puts Jones first (different last name), then Alice Smith before Bob Smith (same last name, first name breaks the tie).
💡

Key Point: thenComparing() is only ever consulted when the comparator before it reports a tie (returns 0) — if every last name were unique, the first-name rule would never actually run.

Complexity
Time Complexity: O(n log n)Space Complexity: O(n)

Why: Chaining more fields makes each individual comparison slightly more expensive when a tie needs breaking, but the number of comparisons the sort itself performs is still O(n log n), the same as a single-field sort.

Key Concepts

Comparator.comparing()thenComparing()multi-field sort

Related Programs