Java - Comparator Interface in Java
The Comparator interface in Java is used to define custom sorting rules for objects. It is especially useful when objects need to be sorted in different ways depending on the requirement.
For example, suppose you have a list of students. You may want to sort them:
-
By name
-
By marks
-
By age
-
By roll number
Instead of changing the Student class every time, you can create different Comparator implementations for different sorting requirements.
1. What is Comparator?
Comparator is an interface available in the java.util package.
Its main purpose is to compare two objects and determine their ordering.
The commonly used method is:
int compare(T o1, T o2)
The return value determines the order:
-
A negative value means
o1should come beforeo2. -
Zero means both objects are considered equal for sorting.
-
A positive value means
o1should come aftero2.
Basic structure:
import java.util.Comparator;
class StudentComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return s1.marks - s2.marks;
}
}
Here, students are compared according to their marks.
2. Why is Comparator Needed?
Consider a Student class:
class Student {
String name;
int age;
int marks;
Student(String name, int age, int marks) {
this.name = name;
this.age = age;
this.marks = marks;
}
}
Suppose you have:
Student s1 = new Student("Rahul", 21, 85);
Student s2 = new Student("Anita", 20, 92);
There is no single obvious way to say which student should come first.
You could sort by:
Name
Age
Marks
Each requirement represents a different ordering.
Comparator allows you to create these different sorting rules without modifying the original Student class.
3. Creating a Comparator Class
A separate class can implement Comparator<Student>.
import java.util.Comparator;
class MarksComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.marks, s2.marks);
}
}
Now the students can be sorted according to their marks.
Example:
import java.util.*;
class Student {
String name;
int age;
int marks;
Student(String name, int age, int marks) {
this.name = name;
this.age = age;
this.marks = marks;
}
@Override
public String toString() {
return name + " " + age + " " + marks;
}
}
class MarksComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s1.marks, s2.marks);
}
}
public class Main {
public static void main(String[] args) {
List<Student> students = new ArrayList<>();
students.add(new Student("Rahul", 21, 85));
students.add(new Student("Anita", 20, 92));
students.add(new Student("Kiran", 22, 78));
Collections.sort(students, new MarksComparator());
for (Student student : students) {
System.out.println(student);
}
}
}
Output:
Kiran 22 78
Rahul 21 85
Anita 20 92
The students are arranged in ascending order of marks.
4. Using Comparator with Collections.sort()
The Collections.sort() method can accept a Comparator.
Syntax:
Collections.sort(list, comparator);
For example:
Collections.sort(students, new MarksComparator());
The comparator tells Java how the objects should be compared.
5. Sorting in Descending Order
The same comparator can be modified to sort marks from highest to lowest.
class MarksComparator implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
return Integer.compare(s2.marks, s1.marks);
}
}
Notice that s2 and s1 are reversed.
The result would be:
Anita 20 92
Rahul 21 85
Kiran 22 78
6. Comparator Using Lambda Expression
A comparator does not always need a separate class.
It can also be written using a lambda expression:
students.sort((s1, s2) -> Integer.compare(s1.marks, s2.marks));
This sorts students by marks in ascending order.
Although lambda expressions provide a shorter syntax, the underlying concept remains the same: a Comparator defines how two objects should be compared.
7. Sorting Objects by Name
A comparator can also sort students alphabetically by name.
students.sort((s1, s2) -> s1.name.compareTo(s2.name));
For example:
Anita
Kiran
Rahul
The compareTo() method of String performs the comparison.
A more concise approach is:
students.sort(Comparator.comparing(s -> s.name));
This tells Java to use the name property as the sorting key.
8. Sorting Objects by Age
Students can similarly be sorted by age:
students.sort(Comparator.comparingInt(s -> s.age));
If the students have ages:
Rahul - 21
Anita - 20
Kiran - 22
The sorted result becomes:
Anita - 20
Rahul - 21
Kiran - 22
9. Sorting by Multiple Fields
One important advantage of Comparator is the ability to define multiple sorting conditions.
Suppose students should first be sorted by marks. If two students have the same marks, they should then be sorted by name.
Comparator<Student> comparator =
Comparator.comparingInt((Student s) -> s.marks)
.thenComparing(s -> s.name);
This creates a two-level sorting rule.
For example:
Anita 85
Kiran 85
Rahul 90
Students with the same marks are then ordered alphabetically.
10. Comparator.reverseOrder()
For objects that already have a natural ordering, Comparator.reverseOrder() can be used to reverse that ordering.
For example:
List<Integer> numbers = Arrays.asList(10, 5, 30, 15);
numbers.sort(Comparator.reverseOrder());
System.out.println(numbers);
Output:
[30, 15, 10, 5]
11. Comparator.reversed()
A comparator can also be reversed using reversed().
Example:
Comparator<Student> marksComparator =
Comparator.comparingInt((Student s) -> s.marks);
students.sort(marksComparator.reversed());
This changes ascending marks into descending marks.
12. Comparator vs Comparable
Comparator is often confused with Comparable. They are related to sorting, but they serve different purposes.
| Comparable | Comparator |
|---|---|
| Defines natural ordering | Defines custom ordering |
Uses compareTo() |
Uses compare() |
Located in java.lang |
Located in java.util |
| Implemented by the class being sorted | Usually implemented separately |
| Generally provides one primary ordering | Can provide multiple different orderings |
For example, if Student naturally sorts by roll number, Comparable may be appropriate.
If the same students sometimes need to be sorted by name, marks, age, or roll number, Comparator is more flexible.
13. Important Features of Comparator
The major features of Comparator are:
-
It allows custom sorting of objects.
-
It keeps sorting logic separate from the class being sorted.
-
Multiple comparators can be created for the same class.
-
It can be used with lists and other sortable collections.
-
It supports ascending and descending order.
-
It can compare objects using multiple fields.
-
It works well with lambda expressions and method references.
-
It is useful when the class's natural ordering is not suitable for a particular requirement.
14. Practical Example
Consider an employee list:
class Employee {
String name;
double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
Employees can be sorted according to salary:
employees.sort(
Comparator.comparingDouble(e -> e.salary)
);
They can instead be sorted according to name:
employees.sort(
Comparator.comparing(e -> e.name)
);
Or sorted according to salary in descending order:
employees.sort(
Comparator.comparingDouble((Employee e) -> e.salary).reversed()
);
The same Employee class can therefore have several different sorting strategies.
Conclusion
The Comparator interface provides a flexible way to control how objects are compared and sorted in Java. Unlike a natural ordering defined inside a class, a comparator allows developers to create different sorting strategies without modifying the original class.
It is particularly useful when working with collections of custom objects such as students, employees, products, customers, or books. By using compare(), comparing(), comparingInt(), thenComparing(), and reversed(), Java programs can implement simple as well as complex sorting requirements efficiently.