Comparator Java Example
In this post, we feature a comprehensive Java comparator Example. We will show how to use java.util.Comparator
interface. java.util.Comparator
is an interface which is used for sorting objects in Java.
The compare(Object o1, Object o2)
method of Comparator
interface needs to be implemented for this purpose, which compares two objects and returns an integer, depending on the comparison: positive, if o1 is greater than o2; zero, if o1 equals to o2; negative, if o1 is less than o1.
Another interface which is used for sorting objects is java.lang.Comparable
. However, Comparable
cannot sort objects on different attributes, while Comparator
can. Also, the method compareTo(T o)
of Comparable
needs to be implemented in this case, which compares the current object (this
object) with the specified object for order. In this example, we will pay attention to Comparator
interface.
1. Example of using Comparator Java interface
We need to use Comparator
interface when we want to order objects on different attributes, for example, let’s suppose that an employer would like to order his employees by salary or by name. This cannot be done using Comparable
interface.
So, let’s see an example. First of all, let’s create a class that will represent the object that will be sorted. Create a java class named Student.java
with the following code:
Student.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | package com.javacodegeeks.java.util.comparator; public class Student { private String name; private int age; private String lesson; private int grade; public Student() { } public Student(String name, int age, String lesson, int grade) { super (); this .name = name; this .age = age; this .lesson = lesson; this .grade = grade; } public String getName() { return name; } public void setName(String name) { this .name = name; } public int getAge() { return age; } public void setAge( int age) { this .age = age; } public String getLesson() { return lesson; } public void setLesson(String lesson) { this .lesson = lesson; } public int getGrade() { return grade; } public void setGrade( int grade) { this .grade = grade; } @Override public String toString() { return "[name=" + this .name + ", age=" + this .age + ", lesson=" + this .lesson + ", grade=" + this .grade + "]" ; } } |
Now, let’s create two classes that will implement the Comparator
interface and they will be used so as to sort students with different attributes.
Firstly, create a java class named GradeComparator.java
with the following code:
GradeComparator.java
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
public class GradeComparator implements Comparator {
public int compare(Student o1, Student o2) {
// descending order (ascending order would be:
// o1.getGrade()-o2.getGrade())
return o2.getGrade() - o1.getGrade();
}
@Override
public int compare(Object o1, Object o2) {
return 0;
}
@Override
public Comparator reversed() {
return null;
}
@Override
public Comparator thenComparing(Comparator other) {
return null;
}
@Override
public Comparator thenComparingInt(ToIntFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparingLong(ToLongFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparingDouble(ToDoubleFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparing(Function keyExtractor) {
return null;
}
@Override
public Comparator thenComparing(Function keyExtractor, Comparator keyComparator) {
return null;
}
}
The above class will sort students by grade, in descending order.
Then, create a java class named NameComparator.java
with the following code:
NameComparator.java
import java.util.Comparator;
import java.util.function.Function;
import java.util.function.ToDoubleFunction;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;
public class NameComparator implements Comparator {
public int compare(Student o1, Student o2) {
String name1 = o1.getName();
String name2 = o2.getName();
// ascending order (descending order would be: name2.compareTo(name1))
return name1.compareTo(name2);
}
@Override
public int compare(Object o1, Object o2) {
return 0;
}
@Override
public Comparator reversed() {
return null;
}
@Override
public Comparator thenComparing(Comparator other) {
return null;
}
@Override
public Comparator thenComparingInt(ToIntFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparingLong(ToLongFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparingDouble(ToDoubleFunction keyExtractor) {
return null;
}
@Override
public Comparator thenComparing(Function keyExtractor) {
return null;
}
@Override
public Comparator thenComparing(Function keyExtractor, Comparator keyComparator) {
return null;
}
}
This class will sort students by Name, in ascending order.
As we mentioned above, classes that implement the Comparator
interface need to override the compare()
method. In this specific example, the sorting of grades will be in descending order as we have reversed the objects o1, o2. For the comparison of names, we used the int compareTo(String anotherString)
method.
Finally, create a java class named MainComparatorExample.java
, which will be the main class of our example:
MainComparatorExample.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | package com.javacodegeeks.java.util.comparator; import java.util.Arrays; public class MainComparatorExample { public static void main(String args[]) { Student student[] = new Student[ 3 ]; student[ 0 ] = new Student(); student[ 0 ].setName( "Nick" ); student[ 0 ].setGrade( 19 ); student[ 1 ] = new Student(); student[ 1 ].setName( "Helen" ); student[ 1 ].setGrade( 12 ); student[ 2 ] = new Student(); student[ 2 ].setName( "Ross" ); student[ 2 ].setGrade( 16 ); System.out.println( "Order of students before sorting is: " ); for ( int i = 0 ; i < student.length; i++) { System.out.println(student[i].getName() + "\t" + student[i].getGrade()); } Arrays.sort(student, new GradeComparator()); System.out .println( "Order of students after sorting by student grade is" ); for ( int i = 0 ; i < student.length; i++) { System.out.println(student[i].getName() + "\t" + student[i].getGrade()); } Arrays.sort(student, new NameComparator()); System.out .println( "Order of students after sorting by student name is" ); for ( int i = 0 ; i < student.length; i++) { System.out.println(student[i].getName() + "\t" + student[i].getGrade()); } } } |
Let’s explain the above code. We create an array of Students, three objects of type Student and then, we set the name and the final grade for each one of them. After that, we print to the output the array without sorting, then we sort the array (a) by grade and (b) by name, and finally, we print to the output the respective results. The sorting can be done by using the method sort(T[] a, Comparator c)
of java.util.Arrays
, which sorts the array of Students according to the order induced by the specified comparator (either NameComparator
or GradeComparator
, respectively).
If we run the above code, we will have the following results:
Output
01 02 03 04 05 06 07 08 09 10 11 12 | Order of students before sorting is: Nick 19 Helen 12 Ross 16 Order of students after sorting by student grade is Nick 19 Ross 16 Helen 12 Order of students after sorting by student name is Helen 12 Nick 19 Ross 16 |
2. Sort Objects on More than one Fields
In this section, we will discuss how to sort objects based on more than one attribute of the object itself. For this, we will use the Comparator interface, which actually allows us to compare objects using compare() methods with more than one attribute.
We will consider the example of the employee class which contains some basic details about the employees. This class implements Comparable
interface to implement the compareTo()
function to show the natural order but also exposes a SalaryComparator
property which is an anonymous class to sort the employees based on Salary
of the employees.
The code is shown below.
Employee.java
import java.util.Comparator;
public class Employee implements Comparable<Employee> {
private int id;
private String name;
private int age;
private long salary;
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public long getSalary() {
return salary;
}
public Employee(int id, String name, int age, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.salary = salary;
}
@Override
public int compareTo(Employee emp) {
return (this.id - emp.id);
}
@Override
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" +
this.salary + "]" + "\n";
}
public static Comparator<Employee> SalaryComparator = new Comparator<Employee>() {
@Override
public int compare(Employee e1, Employee e2) {
return (int) (e1.getSalary() - e2.getSalary());
}
};
}
After this, we have created a class called EmployeeComparatorByIdAndName
, which sorts employees based on Id and name of the employees.
EmployeeComparatorByIdAndName.java
import java.util.Comparator;
public class EmployeeComparatorByIdAndName implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
int flag = o1.getId() - o2.getId();
if (flag == 0) flag = o1.getName().compareTo(o2.getName());
return flag;
}
}
We have created a driver class called ComparatorMultipleAttributeExample
,
ComparatorMultipleAttributeExample.java
import java.util.Arrays;
public class ComparatorMultipleAttributeExample {
public static void main(String[] args) {
Employee[] employeeList = new Employee[4];
employeeList[0] = new Employee(10, "Neo", 25, 100000);
employeeList[1] = new Employee(20, "Dhruv", 29, 200000);
employeeList[2] = new Employee(5, "Akshay", 35, 500000);
employeeList[3] = new Employee(1, "Abhay", 32, 5000);
//sorting employees array using Comparable interface implementation
Arrays.sort(employeeList);
System.out.println("Default Sorting of Employees list:\n" + Arrays.toString(employeeList));
//sort employees array using Comparator by Salary
Arrays.sort(employeeList, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n" + Arrays.toString(employeeList));
//Employees list sorted by ID and then name using Comparator class
employeeList[0] = new Employee(1, "Gagan", 25, 10000);
Arrays.sort(employeeList, new EmployeeComparatorByIdAndName());
System.out.println("Employees list sorted by ID and Name:\n" + Arrays.toString(employeeList));
}
}
The output of ComparatorMultipleAttributeExample.java
is shown in snapshot below.
3. The Comparing Method
From our Java 8 Comparator example:
The comparator has a new method i.e. comparing()
which uses an instance of the java.util.function.Function
functional interface. This method is specified by using the lambda expressions or its equivalent method reference for creating the Comparator instance. The comparing()
method has the following signature.
1 | static <T,U extends Comparable<? super U>> Comparator<T> comparing(Function<? super T,? extends U> keyE |
This method works by taking a Function<T,R>
functional interface instance as an input, where T
is the type of input object and R
is the sort key which is returned (or extracted) from the input object when Function<T,R>
processes it. In addition, developers can now implement the multiple sort criteria’s which can be clubbed using the comparing()
method with a thenComparing()
method. Java8 Comparator provides a default method thenComparing()
which has the following signature.
1 | default Comparator<T> thenComparing(Comparator<? super T> other) |
This method does the second level sorting if in case the first level sorting is indecisive.
4. Comparable V/s Comparator
So how do we decide when to use Comparable
interface and when to use Comparator
interface. It depends on the use-case basically.
Just to give a comparative analysis,Comparable
provides sorting based on one attribute of the object only with natural ordering and Comparator
interface lets you sort objects based on more that one attribute.
Comparable
interface implements the sorting logic using compareTo()
method in the current class, i.e., the sorting logic is coupled with the class implementing the Comparable interface. On the other hand, Comparator
interface implements the sorting logic using compare()
method, in a separate class, which increases decoupling.
Comparable
is present in java.lang package and Comparator
is present in the java.util package.
5. Download the source code
This was an example of Comparator
.
Download the Eclipse project from here: Comparator Java Example
Last Updated on Feb. 3rd, 2020
It would have been better to read about comparing by multiple fields and how you could achieve that using different approaches: implementing by hand, using the CompareToBuilder (apache lang, before jdk8) or using the streaming API (in case of Java8). And of course, the code above should have been nullsafe.