Comparable & Comparator
IntermediateDefine natural ordering with Comparable and flexible multi-field sorting with Comparator — the two pillars of Java sorting.
Overview
Comparable defines a class's natural ordering via compareTo(). It is implemented by the class itself and used by Collections.sort(), TreeSet, and TreeMap by default. Comparator is a separate strategy object that defines an external ordering without modifying the class. Java 8 gave Comparator a rich static/default method API for chaining, null handling, and reversing — making complex multi-field sorts readable one-liners.
Implementing Comparable
compareTo returns negative if this < other, zero if equal, positive if this > other. The contract: it must be consistent with equals (compareTo == 0 implies equals() == true), transitive, and antisymmetric.
Never compute a - b as a compareTo shortcut for integers — it overflows. Use Integer.compare(a, b) instead.
import java.util.*;
public class ComparableDemo implements Comparable<ComparableDemo> {
private final String name;
private final int priority;
public ComparableDemo(String name, int priority) {
this.name = name; this.priority = priority;
}
@Override
public int compareTo(ComparableDemo other) {
// Primary: priority ascending
int cmp = Integer.compare(this.priority, other.priority);
if (cmp != 0) return cmp;
// Secondary: name alphabetically
return this.name.compareTo(other.name);
}
@Override public String toString() { return name + "(" + priority + ")"; }
public static void main(String[] args) {
List<ComparableDemo> tasks = new ArrayList<>(List.of(
new ComparableDemo("Deploy", 2),
new ComparableDemo("Test", 1),
new ComparableDemo("Build", 1),
new ComparableDemo("Review", 2)
));
Collections.sort(tasks); // uses compareTo
System.out.println(tasks); // [Build(1), Test(1), Deploy(2), Review(2)]
TreeSet<ComparableDemo> set = new TreeSet<>(tasks);
System.out.println(set.first()); // Build(1)
}
}Comparator API — Chaining & Composition
Comparator.comparing(keyExtractor) — creates a Comparator from a key function thenComparing(keyExtractor) — secondary sort reversed() — flip order nullsFirst / nullsLast — handle nulls Comparator.naturalOrder() / reverseOrder() — standard orders
import java.util.*;
import java.util.stream.*;
public class ComparatorChaining {
record Employee(String name, String dept, double salary) {}
public static void main(String[] args) {
List<Employee> emps = List.of(
new Employee("Alice", "Engineering", 95000),
new Employee("Bob", "Marketing", 72000),
new Employee("Carol", "Engineering", 88000),
new Employee("Dave", "Marketing", 72000)
);
// Sort by dept asc, then salary desc, then name asc
Comparator<Employee> comp = Comparator
.comparing(Employee::dept)
.thenComparingDouble(Employee::salary).reversed()
// reversed() flips the whole chain — careful!
;
// Better: build each step explicitly
Comparator<Employee> precise = Comparator
.comparing(Employee::dept)
.thenComparing(Comparator.comparingDouble(Employee::salary).reversed())
.thenComparing(Employee::name);
emps.stream()
.sorted(precise)
.forEach(e -> System.out.println(e.dept() + " | " + e.name() + " | " + e.salary()));
// Engineering | Alice | 95000.0
// Engineering | Carol | 88000.0
// Marketing | Bob | 72000.0
// Marketing | Dave | 72000.0
// Null handling
List<String> withNulls = new ArrayList<>(Arrays.asList("banana", null, "apple", null));
withNulls.sort(Comparator.nullsLast(Comparator.naturalOrder()));
System.out.println(withNulls); // [apple, banana, null, null]
// Reverse natural order
List<Integer> nums = new ArrayList<>(List.of(3,1,4,1,5,9));
nums.sort(Comparator.reverseOrder());
System.out.println(nums); // [9, 5, 4, 3, 1, 1]
}
}Comparable vs Comparator — Decision Guide
Use Comparable when the class has one obvious natural order (Integer, String, LocalDate all do this). Use Comparator when: you need multiple orderings, you cannot modify the class, or the ordering is context-dependent (sort products by price for one page, by rating for another).
import java.util.*;
public class ComparableVsComparator {
record Product(String name, double price, double rating) {}
public static void main(String[] args) {
List<Product> products = List.of(
new Product("Laptop", 999.0, 4.5),
new Product("Phone", 699.0, 4.7),
new Product("Tablet", 499.0, 4.2)
);
// Different orderings as named Comparators
Comparator<Product> byPrice = Comparator.comparingDouble(Product::price);
Comparator<Product> byRating = Comparator.comparingDouble(Product::rating).reversed();
Comparator<Product> byName = Comparator.comparing(Product::name);
System.out.println("By price:");
products.stream().sorted(byPrice)
.forEach(p -> System.out.println(" " + p.name() + " $" + p.price()));
System.out.println("By rating desc:");
products.stream().sorted(byRating)
.forEach(p -> System.out.println(" " + p.name() + " ★" + p.rating()));
// Using max/min with Comparator
Product cheapest = products.stream().min(byPrice).orElseThrow();
Product topRated = products.stream().max(Comparator.comparingDouble(Product::rating)).orElseThrow();
System.out.println("Cheapest: " + cheapest.name());
System.out.println("Top rated: " + topRated.name());
}
}Key Points to Remember
- compareTo: negative if this < other, 0 if equal, positive if this > other
- Never use a - b in compareTo — integer overflow; use Integer.compare(a, b)
- compareTo must be consistent with equals; inconsistency breaks TreeSet/TreeMap
- Comparator.comparing(keyFn).thenComparing(...) builds multi-level sorts cleanly
- reversed() flips the entire chain — attach it to individual steps to flip only one level
- nullsFirst / nullsLast wrap any Comparator to handle null keys without NPE
Practice Comparable & Comparator in the Playground
Run and modify code directly in your browser - no setup needed.
Interview Questions
Sign in to ask AriaWhat is the difference between Comparable and Comparator?
Why should you not use subtraction in compareTo for integers?
How do you sort a list by multiple fields using Comparator?
What happens if compareTo is not consistent with equals in a TreeSet?
How do you sort a list in reverse natural order using Comparator?
Ask Aria about Comparable & Comparator
Your personal AI tutor — ask anything about this concept