In this tutorial, we will see the Java Comparator example to sort an Employee object by name, age, and salary. In order to sort Employee object on different criteria, we need to create multiple comparators e.g. NameComparator, AgeComparator, and SalaryComparator, this is known as custom sorting in Java. This is different from the natural ordering of objects, provided by the compareTo() method of java.lang.Comparable interface. Though both compare() and compareTo() method looks similar they are different in the sense that, former accepts one parameter, while later accepts two-parameter. Former compare passed object to the current object, on the other hand, compare() method compares two different objects passed to it.
You can create this comparator as a nested static class because they require access to private members of the class.
Once you create these Comparator implementations, all you need to do is to override compare() method accordingly e.g. in compare() method of NameComparator compare the name of two employees and return positive if the name of the first employee is greater than the second, and return negative if the name of the first employee is less than second and return zero if the name of both employees is equal.
By using Generics, you can avoid casting an object into the Employee inside compare() method, as shown in the example of this article. Once you have your Comparator classes ready, you can create a bunch of employees and sort them using any Comparator by passing List of employees and Comparator into Collections.sort(List, Comparator) method.
By the way, this Java example also implements equals(), hashcode(), compareTo(), and toString() method for Employee object, along with JUnit test for testing various Comparator implementation in file EmployeeTest.java.
And, If you are new to the Java world then I also recommend you go through The Complete Java MasterClass on Udemy to learn Java in a better and more structured way. This is one of the best and up-to-date courses to learn Java online.
You can create this comparator as a nested static class because they require access to private members of the class.
Once you create these Comparator implementations, all you need to do is to override compare() method accordingly e.g. in compare() method of NameComparator compare the name of two employees and return positive if the name of the first employee is greater than the second, and return negative if the name of the first employee is less than second and return zero if the name of both employees is equal.
By using Generics, you can avoid casting an object into the Employee inside compare() method, as shown in the example of this article. Once you have your Comparator classes ready, you can create a bunch of employees and sort them using any Comparator by passing List of employees and Comparator into Collections.sort(List, Comparator) method.
By the way, this Java example also implements equals(), hashcode(), compareTo(), and toString() method for Employee object, along with JUnit test for testing various Comparator implementation in file EmployeeTest.java.
And, If you are new to the Java world then I also recommend you go through The Complete Java MasterClass on Udemy to learn Java in a better and more structured way. This is one of the best and up-to-date courses to learn Java online.
Custom Sorting in Java using Comparator Example
Here is the complete code of creating different Comparator classes to compare objects on different attributes. In our example, we have an Employee object, which has fields like int id, String name, int salary, int age, and Date field to represent the date of joining. Our requirement is to sort a List of employees based upon their name, age, salary, and date of joining.For this purpose, we have created four different comparator classes namely NameComparator, AgeComparator, SalaryComparator, and DOJComparator.
All classes implement java.util.Comparator interface but their compare() method are overridden differently e.g. first one compares the name of two employee object, second compare their salary, third compare their age and last one compares their age.
When overriding compare() method, if you find an object, which overrides compareTo() then invoke that, for example for comparing String and Date we are invoking their compareTo() methods.
Files to run this Example
Employee.java
EmployeeTest.java
In order to run this program, simply copy-paste the following two classes into two different Java source files. Then name them according to the name of the public class e.g. Employee.java and EmployeeTest.java. You also need JUnit to run a test file, which tests the code you have written for implementing Comparator and overriding compare() method.
You can run it on Eclipse or command prompt as per your convenience. If you are not using JUnit then you just put the test code inside the main method of any class and run it accordingly.
That's all on this Java Comparator example tutorial. We have learned how to create multiple Comparators in a class for comparing objects in different parameters. This allows you to sort objects in any custom order, depending upon business requirements.
Employee.java
===============
import java.util.Comparator;
import java.util.Date;
/**
*
* @author
*/
public class Employee implements Comparable<Employee>{
private int id;
private String name;
private int salary;
private int age;
private Date dateOfJoining;
public static final Comparator<Employee> AgeComparator = new Comparator<Employee>(){
@Override
public int compare(Employee o1, Employee o2) {
return o1.age - o2.age; // This will work because age is positive integer
}
};
public static final Comparator<Employee> SalaryComparator = new Comparator<Employee>(){
@Override
public int compare(Employee o1, Employee o2) {
return o1.salary - o2.salary; // salary is also positive integer
}
};
public static final Comparator<Employee> NameComparator = new Comparator<Employee>(){
@Override
public int compare(Employee o1, Employee o2) {
return o1.name.compareTo(o2.name);
}
};
public static final Comparator<Employee> DOJComparator = new Comparator<Employee>(){
@Override
public int compare(Employee o1, Employee o2) {
return o1.dateOfJoining.compareTo(o2.dateOfJoining);
}
};
public Employee(int id, String name, int salary, int age, Date dateOfJoining) {
this.id = id;
this.name = name;
this.salary = salary;
this.age = age;
this.dateOfJoining = dateOfJoining;
}
@Override
public String toString() {
return "Employee{" + "id=" + id + ", name=" + name + ", salary=" + salary + ", age=" + age + ", dateOfJoining=" + dateOfJoining + '}';
}
@Override
public int compareTo(Employee o) {
return this.id - o.id;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Employee other = (Employee) obj;
if (this.id != other.id) {
return false;
}
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.salary != other.salary) {
return false;
}
if (this.age != other.age) {
return false;
}
if (this.dateOfJoining != other.dateOfJoining && (this.dateOfJoining == null || !this.dateOfJoining.equals(other.dateOfJoining))) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 5;
hash = 47 * hash + this.id;
hash = 47 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 47 * hash + this.salary;
hash = 47 * hash + this.age;
hash = 47 * hash + (this.dateOfJoining != null ? this.dateOfJoining.hashCode() : 0);
return hash;
}
}
EmployeeTest.java
==================
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test class to test sorting of Employee object on different parameters.
* each test method will test each Comparator implementation.
* @author http://javarevisited.blogpot.com
*/
public class EmployeeTest {
@Test
public void testEmployeeSorting(){
Employee e1 = new Employee(1, "A", 1000, 32, new Date(2011, 10, 1));
Employee e2 = new Employee(2, "AB", 1300, 22, new Date(2012, 10, 1));
Employee e3 = new Employee(3, "B", 10, 42, new Date(2010, 11, 3));
Employee e4 = new Employee(4, "CD", 100, 23, new Date(2011, 10, 1));
Employee e5 = new Employee(5, "AAA", 1200, 26, new Date(2011, 10, 1));
List<Employee> listOfEmployees = new ArrayList<Employee>();
listOfEmployees.add(e1);
listOfEmployees.add(e2);
listOfEmployees.add(e3);
listOfEmployees.add(e4);
listOfEmployees.add(e5);
System.out.println("Unsorted List : " + listOfEmployees);
Collections.sort(listOfEmployees); //Sorting by natural order
assertEquals(e1, listOfEmployees.get(0));
assertEquals(e5, listOfEmployees.get(4));
Collections.sort(listOfEmployees, Employee.NameComparator);
assertEquals(e1, listOfEmployees.get(0));
assertEquals(e4, listOfEmployees.get(4));
Collections.sort(listOfEmployees, Employee.AgeComparator);
assertEquals(e2, listOfEmployees.get(0));
assertEquals(e3, listOfEmployees.get(4));
Collections.sort(listOfEmployees, Employee.SalaryComparator);
assertEquals(e3, listOfEmployees.get(0));
assertEquals(e2, listOfEmployees.get(4));
Collections.sort(listOfEmployees, Employee.DOJComparator);
assertEquals(e3, listOfEmployees.get(0));
assertEquals(e2, listOfEmployees.get(4));
}
}
That's all on this Java Comparator example tutorial. We have learned how to create multiple Comparators in a class for comparing objects in different parameters. This allows you to sort objects in any custom order, depending upon business requirements.
You can provide a custom Comparator is a nested static class because a Comparator is closely associated with the object it compares.
This is one of the genuine usages of nested static classes in Java. It's good to provide natural ordering of objects via the compareTo() method and provide additional compare() methods for custom sorting of objects in Java.
Always use Generics while overriding compare(), this will make your program as now your compare() will accept two Employee objects, instead of two java.lang.Object parameters.
Other Java Collection tutorials you may like
Thanks for reading this article so far. If you like this article then please share it with your friends and colleagues. If you have any questions or feedback then please drop a comment.
Other Java Collection tutorials you may like
- How to sort a Map by keys and values in Java? (tutorial)
- How to sort an ArrayList in ascending and descending order in Java? (tutorial)
- What is the difference between ArrayList and HashSet in Java? (answer)
- What is the difference between TreeMap and TreeSet in Java? (answer)
- What is the difference between HashMap and ConcurrentHashMap in Java? (answer)
- The difference between HashSet and TreeSet in Java? (answer)
- The difference between ArrayList and LinkedList in Java? (answer)
- The difference between Vector and ArrayList in Java? (answer)
Thanks for reading this article so far. If you like this article then please share it with your friends and colleagues. If you have any questions or feedback then please drop a comment.
Nice article , but there are not static nested class(NameComparator, AgeComparator, SalaryComparator and DOJComparator), I would say there are static anonymous class.
ReplyDeleteEquals can not be simplier?
ReplyDeleteA small correction - Instead of "Though both compare() and compareTo() method looks similar they are different in a sense that, FORMER accept one parameter, while LATER accept two parameter."
ReplyDelete, it should be former (compare())accept two parameters and later(compareTo()) accepts one parameter
How to run this program
ReplyDeleteFrom Java 8 onwards you can use lambda expression instead of anonymous class to implement custom comparator. You can also use method reference and some useful methods like Comparator::comparing() to sort with multiple attributes.
ReplyDeleteFor example, your code for sorting employees based upon salary can be re-written in Java 8 as follows :
Collections.sort(employees, Comparator.comparing(Employee::salary));
This will sort all employees on increasing order of salary, but if you want to sort in decreasing order, you can just do this :
Collections.sort(employees, Comparator.comparing(Employee::salary).reversed());
That's the power of Java 8, clear, concise and succint code.
Nice article, but there are some mistakes in example. Syntax of compare() and compareTo() are not correct. For Example, Instead of public int compare(Employee o1, Employee o2) , It should be public int compare(Object o1, Object o2)
ReplyDeletePlease correct the example.
Instead of
As Comparator is an interface, how we can create an object for Comparator using new Keyword.
ReplyDeletepublic static final Comparator DOJComparator = new Comparator()
@Chandra, look at closely mate, we are using Anonymous class, which means a class which implements Comparator interface and that's why we are able to create instance using new() keyword. The logic of implementation is always in the overridden compare() method.
ReplyDeleteGreat article. I never thought of using anonymous class comparator to solve many sorting criteria within pojo, thanks a bunch.
ReplyDeleteHello Javin. Recently i was asked in interview. Suppose i have a list of heterogeneous objects e.g. Student,employee,person,etc. Each having a common property firstName, how to write a comparator for it and it should not do any instanceOf checking.
ReplyDeleteHello friends, I was asked a question in an interview regarding comparator interface, they ask me how to sort employee id & employee name using only one comparator class. you can't create two separate comparator class for id comparator & name comparator.Sorting must be customized sorting order. Please one body answer me.
ReplyDeleteCollections.sort(listOfEmployees, Employee.NameComparator);
ReplyDeletecan you explain the above code?
what happens when i call sort method, how does the flow goes
@Anonymous, when you call the sort method, you give a list of employee and a Comparator to compare them. The Java uses a modified version of Mergesort to sort the list of employee and for comparing two employee it uses the Comparator you have provided.
ReplyDeleteHello @Kanhu, are they after a Comparator which first sort on ID and then on NAME? e.g. if two employee have same id then check their name? if yes then it's possible, you can do that in compare() method, just check if id is equal first if they are then check if name is equal then return 0 or 1 or -1 accordingly e.g.
ReplyDeleteif(obj1.id === obj2.id){
if(obj1.name.equals(obj2.name)){
return 0;
}else{
...
}
}else{
if(obj1.id > obj2.id){ return 1;}
else{
return -1;
}
}
I have question please clarify . When we use
ReplyDeleteCollections.sort(employees, Comparator.comparing(Employee::salary));
That means now we do not need inner classes like SalaryComparator that implement comparator interface. Also in this case it's just enough if employee classs implements Comparable interface right ?