Java Comparator Interface

The Comparator interface in Java is used to define custom ordering logic for objects.
It allows you to sort objects externally, without modifying the class whose objects are being compared.

Introduced in java.util, Comparator is a cornerstone of sorting, ordering, and stream-based operations.


Why Comparator Exists

Java provides two ways to define sorting:

  1. Comparable → Natural ordering (inside the class)
  2. Comparator → Custom ordering (outside the class)

Comparator is used when:

  • You cannot modify the class
  • You want multiple sorting strategies
  • Sorting logic should be decoupled from the model

Comparator vs Comparable

Feature Comparable Comparator
Package java.lang java.util
Method compareTo() compare()
Modifies class Yes No
Multiple orderings No Yes
Lambda-friendly Limited Yes

Comparator Interface Definition

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
}

Return values meaning

Return Meaning
< 0 o1 comes before o2
0 o1 equals o2
> 0 o1 comes after o2

Simple Example

Sorting integers in descending order

Comparator<Integer> desc = (a, b) -> b - a;
Collections.sort(list, desc);

Sorting Custom Objects

Example class

class Employee {
    int id;
    String name;
    double salary;
}

Sort by salary (ascending)

Comparator<Employee> bySalary =
    (e1, e2) -> Double.compare(e1.salary, e2.salary);

Collections.sort(employees, bySalary);

Sort by name (alphabetical)

Comparator<Employee> byName =
    (e1, e2) -> e1.name.compareTo(e2.name);

Comparator with Lambda Expressions

Since Comparator is a functional interface, lambdas work naturally.

employees.sort((a, b) -> a.id - b.id);

Cleaner alternative:

employees.sort(Comparator.comparing(e -> e.id));

Comparator Utility Methods (Java 8+)

comparing()

Comparator<Employee> bySalary =
    Comparator.comparing(Employee::getSalary);

reversed()

Comparator<Employee> bySalaryDesc =
    Comparator.comparing(Employee::getSalary).reversed();

thenComparing() (Multiple conditions)

Comparator<Employee> byDeptThenSalary =
    Comparator.comparing(Employee::getDepartment)
              .thenComparing(Employee::getSalary);

Null Handling

nullsFirst()

Comparator<Employee> comp =
    Comparator.nullsFirst(
        Comparator.comparing(Employee::getName)
    );

nullsLast()

Comparator<Employee> comp =
    Comparator.nullsLast(
        Comparator.comparing(Employee::getName)
    );

Comparator with Streams

List<Employee> sorted =
    employees.stream()
             .sorted(Comparator.comparing(Employee::getSalary))
             .toList();

Descending:

employees.stream()
         .sorted(Comparator.comparing(Employee::getSalary).reversed())
         .toList();

Sorting Maps Using Comparator

Sort Map by Key

Map<String, Integer> sorted =
    new TreeMap<>(Comparator.reverseOrder());

Sort Map Entries by Value

map.entrySet()
   .stream()
   .sorted(Map.Entry.comparingByValue())
   .forEach(System.out::println);

Comparator in TreeSet / TreeMap

Tree-based collections rely on Comparator for ordering.

Set<Employee> set =
    new TreeSet<>(Comparator.comparing(Employee::getId));

⚠️ Comparator must ensure consistent ordering, or elements may be lost.


Common Pitfalls

❌ Subtraction for comparison

(a, b) -> a - b   // may overflow

✅ Use:

Integer.compare(a, b);

❌ Inconsistent comparison

Returning random or inconsistent values breaks TreeSet / TreeMap.


❌ Forgetting equals contract

Comparator should be consistent with equals where possible.


Comparator vs equals()

  • equals() checks logical equality
  • Comparator checks ordering
  • They serve different purposes

Real-World Use Cases

  • Sorting search results
  • Ordering leaderboard data
  • Multi-level sorting (date → priority → name)
  • Custom UI sorting
  • Stream pipelines

Interview Tips 🎯

  • Prefer Comparator.comparing() over manual lambdas
  • Mention immutability and reusability
  • Avoid subtraction comparisons
  • Explain difference between Comparable and Comparator clearly

Summary

  • Comparator defines external sorting logic
  • Supports multiple sorting strategies
  • Functional, composable, and stream-friendly
  • Essential for clean, flexible ordering logic

One-line takeaway

Comparator lets you decide how objects should be ordered without touching the object itself.


This site uses Just the Docs, a documentation theme for Jekyll.