Comparator Interface in Java
The Comparator interface in Java is used to define a custom ordering for objects, written outside the class being sorted. While Comparable gives a class one natural order, you can create any number of comparators: one to sort students by name, another by marks, another by marks in reverse. A comparator is passed to methods such as list.sort, Collections.sort and new TreeSet<>(comparator). In this lesson, you will learn how to write comparators, from a full class to a one-line lambda.
Declaration
@FunctionalInterface
public interface Comparator<T> {
int compare(T a, T b);
// plus many default and static helper methods
}Comparator is in the java.util package. compare(a, b) follows the same sign rule as compareTo: negative if a comes first, zero if equal, positive if b comes first.
Why Use Comparator
- To sort a class in more than one way.
- To sort a class you cannot change, such as one from a library.
- To sort in an order different from the natural one, such as strings by length.
Example: Three Ways to Write a Comparator
Let's see an example that sorts the same list using a class, an anonymous class and a lambda.
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ComparatorWays {
static class ByLength implements Comparator<String> {
@Override
public int compare(String a, String b) {
return Integer.compare(a.length(), b.length());
}
}
public static void main(String[] args) {
List<String> names = new ArrayList<>(
List.of("Srihitha", "Navika", "Advitha", "Anamaneni"));
names.sort(new ByLength());
System.out.println("By length: " + names);
names.sort(new Comparator<String>() {
@Override
public int compare(String a, String b) {
return b.compareTo(a);
}
});
System.out.println("Reverse: " + names);
names.sort((a, b) -> a.compareTo(b));
System.out.println("Natural: " + names);
}
}By length: [Navika, Advitha, Srihitha, Anamaneni]
Reverse: [Srihitha, Navika, Anamaneni, Advitha]
Natural: [Advitha, Anamaneni, Navika, Srihitha]Explanation: ByLength is a normal class that compares string lengths. The anonymous class reverses the order by comparing b with a. The lambda (a, b) -> a.compareTo(b) is the shortest form; it works because Comparator is a functional interface with one abstract method.
Helper Methods of Comparator
| Method | Description |
|---|---|
static comparing(Function key) | It creates a comparator that compares by the given key, such as Student::name. |
static comparingInt(ToIntFunction key) | It compares by an int key without boxing. |
reversed() | It returns a comparator with the opposite order. |
thenComparing(...) | It adds a second comparison for ties. |
static naturalOrder() | It returns the natural (Comparable) order. |
static reverseOrder() | It returns the reverse of the natural order. |
static nullsFirst(Comparator c) | It puts null values before all others. |
static nullsLast(Comparator c) | It puts null values after all others. |
Example: Comparator.comparing with a Record
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class ComparingDemo {
record Student(String name, int marks) { }
public static void main(String[] args) {
List<Student> list = new ArrayList<>(List.of(
new Student("Navika", 91),
new Student("Srihitha", 78),
new Student("Advitha", 85)));
list.sort(Comparator.comparing(Student::name));
System.out.println(list);
list.sort(Comparator.comparingInt(Student::marks).reversed());
System.out.println(list);
}
}[Student[name=Advitha, marks=85], Student[name=Navika, marks=91], Student[name=Srihitha, marks=78]]
[Student[name=Navika, marks=91], Student[name=Advitha, marks=85], Student[name=Srihitha, marks=78]]Explanation: Comparator.comparing(Student::name) builds a comparator from the name of each student. comparingInt(Student::marks).reversed() sorts by marks from highest to lowest. No compare method had to be written by hand.
Common Mistakes
Writing (a, b) -> a.marks() - b.marks(). Subtraction can overflow; use comparingInt.
Calling reversed() in the wrong place in a chain. It reverses everything before it (see "Comparator Chaining in Java").
Sorting a list that contains null. Wrap the comparator in Comparator.nullsFirst(...) or nullsLast(...).
Interview Corner
What is the Comparator interface?
Comparator<T> in java.util is a functional interface whose method int compare(T a, T b) defines an ordering outside the class being compared. It lets you sort objects in many different ways, or sort classes you can't modify. It provides helpers such as comparing, comparingInt, thenComparing, reversed, naturalOrder, nullsFirst and nullsLast, and is usually written as a lambda or method reference.
Practice
- Easy: Sort a list of five city names by their last letter using a lambda comparator.
- Harder: Sort a
List<Student>by name length, then print it again sorted by marks from lowest to highest, using onlyComparatorhelper methods.
Key Takeaways
Was this tutorial helpful?