Many time we need to sort arraylist of objects by field or alphabetically, especially if you are working on a domain where people are your main entities (e.g. HR), you will encounter this requirement more frequently. There are many ways to sort such lists, which ranges from sorting on client UI using javascript to sort arraylist of objects on server side using complex algorithm, and sometimes in database too.
If you DO NOT have millions of records for sorting at a time (for which DB query is best way), I will recommend you to consider Comparable
or Comparator interfaces.
Table of Contents 1. Employee - Model Class 2. Comparable Interface 3. Comparator Interface 4. Comparator in Java 8 5. SortedSet and SortedMap 6. hashCode() and equals()
1. Employee – Model Class
Our Employee
class is plain old class with four fields: id
, firstName
, lastName
and age
. I have chosen these fields purposefully.
package corejava.compare; public class Employee { private int id = -1; private String firstName = null; private String lastName = null; private int age = -1; public Employee(int id, String fName, String lName, int age) { this.id = id; this.firstName = fName; this.lastName = lName; this.age = age; } // Setters and Getters @Override public String toString() { return "Employee : " + id + " - " + firstName + " - " + lastName + " - " + age + "n"; } }
2. Java sort arraylist of objects – Comparable Example
Comparable
interface provides one method compareTo(T o) to implement in any class so that two instances of that class can be compared.
Method syntax is:
public int compareTo(T o);
Here, out of two instances to compare, one is instance itself on which method will be invoked, and other is passed as parameter o
.
Lets see how our Employee
class will look after implementing Comparable
interface.
package corejava.compare; public class Employee implements Comparable<Employee> { private int id = -1; private String firstName = null; private String lastName = null; private int age = -1; public Employee(int id, String fName, String lName, int age) { this.id = id; this.firstName = fName; this.lastName = lName; this.age = age; } @Override public int compareTo(Employee o) { return this.id - o.id; } // Setters and Getters @Override public String toString() { return "Employee : " + id + " - " + firstName + " - " + lastName + " - " + age + "\n"; } }
Default way to sort list of employees, in our case, is by their id
. Whatever, your default sorting order is, use in compare()
method.
In implemented compare()
method, we have simply returned the difference in employee ids of two instances. Two equal employee ids will return zero, indicating the same object.
2.1. Collections.sort()
Lets test our compare()
method implemented in above Employee
class.
package corejava.compare; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class TestSorting { public static void main(String[] args) { Employee e1 = new Employee(1, "aTestName", "dLastName", 34); Employee e2 = new Employee(2, "nTestName", "pLastName", 30); Employee e3 = new Employee(3, "kTestName", "sLastName", 31); Employee e4 = new Employee(4, "dTestName", "zLastName", 25); List<Employee> employees = new ArrayList<Employee>(); employees.add(e2); employees.add(e3); employees.add(e1); employees.add(e4); // UnSorted List System.out.println(employees); Collections.sort(employees); // Default Sorting by employee id System.out.println(employees); } }
In the above program, first print statement prints an unsorted list of employees and in the second print statement, employees are sorted by their employee id.
//Unsorted [Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 1 - aTestName - dLastName - 34 , Employee : 4 - dTestName - zLastName - 25] //Sorted [Employee : 1 - aTestName - dLastName - 34 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 4 - dTestName - zLastName - 25]
3. Java sort arraylist of objects – Comparator Example
So, now we can sort a list of employees by their id
. Now let’s consider a case where we want to sort employees list based on some user input which is essentially sorting field i.e. sometimes he wants to sort by first name
, sometimes sort by age
also.
This can be achieved by jquery plugins easily, but what if browser has disables the javascript. You will have to sort the list on the server side only to not break the application functionality.
Here comes the Comparator
interface to rescue you. A Comparator
can be used to sort a collection of instances on some particular basis. To sort of different fields, we need multiple Comparator implementations.
3.1. Comparator interface example
We have determined multiple implementations for different sorting cases. Let’s write them.
3.1.1. First name sorter
package corejava.compare; import java.util.Comparator; public class FirstNameSorter implements Comparator<Employee>{ @Override public int compare(Employee o1, Employee o2) { return o1.getFirstName().compareTo(o2.getFirstName()); } }
3.1.2. Last name sorter
package corejava.compare; import java.util.Comparator; public class LastNameSorter implements Comparator<Employee> { @Override public int compare(Employee o1, Employee o2) { return o1.getLastName().compareTo(o2.getLastName()); } }
3.1.3. Age sorter
package corejava.compare; import java.util.Comparator; public class AgeSorter implements Comparator<Employee> { @Override public int compare(Employee o1, Employee o2) { return o1.getAge() - o2.getAge(); } }
3.2. How to compare with Comparator
So theoretically, we should be able to sort of any field at our wish with minimum code. Let’s see if we really are:
package corejava.compare; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class TestSorting { public static void main(String[] args) { Employee e1 = new Employee(1, "aTestName", "dLastName", 34); Employee e2 = new Employee(2, "nTestName", "pLastName", 30); Employee e3 = new Employee(3, "kTestName", "sLastName", 31); Employee e4 = new Employee(4, "dTestName", "zLastName", 25); List<Employee> employees = new ArrayList<Employee>(); employees.add(e2); employees.add(e3); employees.add(e1); employees.add(e4); // UnSorted List System.out.println(employees); Collections.sort(employees); // Default Sorting by employee id System.out.println(employees); Collections.sort(employees, new FirstNameSorter()); // Sorted by firstName System.out.println(employees); Collections.sort(employees, new LastNameSorter()); // Sorted by lastName System.out.println(employees); Collections.sort(employees, new AgeSorter()); // Sorted by age System.out.println(employees); } } Output: //Unsorted [Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 1 - aTestName - dLastName - 34 , Employee : 4 - dTestName - zLastName - 25] //Default sorting based on employee id [Employee : 1 - aTestName - dLastName - 34 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 4 - dTestName - zLastName - 25] //Sorted by first name [Employee : 1 - aTestName - dLastName - 34 , Employee : 4 - dTestName - zLastName - 25 , Employee : 3 - kTestName - sLastName - 31 , Employee : 2 - nTestName - pLastName - 30] //Sorted by last name [Employee : 1 - aTestName - dLastName - 34 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 4 - dTestName - zLastName - 25] //Sorted by age [Employee : 4 - dTestName - zLastName - 25 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 1 - aTestName - dLastName - 34]
Above class’s output shows clearly, now we are able to sort the list of employees on any field using appropriate Comparator
implementation.
4. Comparator in Java 8
Latest Lambda changes have made using Comparator
a lot easier than ever before.
List<Employee> employees = getEmployeesFromDB(); //Sort all employees by first name employees.sort(Comparator.comparing(e -> e.getFirstName())); //OR you can use below employees.sort(Comparator.comparing(Employee::getFirstName)); //Sort all employees by first name in reverse order Comparator<Employee> comparator = Comparator.comparing(e -> e.getFirstName()); employees.sort(comparator.reversed()); //Sorting on multiple fields; Group by. Comparator<Employee> groupByComparator = Comparator.comparing(Employee::getFirstName).thenComparing(Employee::getLastName); employees.sort(groupByComparator);
Read More: Java 8 Comparator Example
5. Java sort arraylist of objects – SortedSet and SortedMap
Its important to understand the importance of both interfaces in code collection APIs which provide implicit behavior sort list of objects by property. Such APIs are for example SortedMap or SortedSet.
These collections store elements in sorted order. To determining the sorting, they also use compare()
method. Always remember if you Employee class does not implement Comparable
interface and you are not using Comparator
also, then adding elements in sorted collections will give you error.
Exception in thread "main" java.lang.ClassCastException: corejava.compare.Employee cannot be cast to java.lang.Comparable at java.util.TreeMap.put(Unknown Source) at java.util.TreeSet.add(Unknown Source) at corejava.compare.SortedSetTest.main(SortedSetTest.java:17)
So, it is necessary to use either of both interfaces to able to store instances in sorted collections.
5.1. SortedSet with Comparable
If you are not using Comparator
implementation, then Employee
class’s compare()
method will be used for sorting.
package corejava.compare; import java.util.SortedSet; import java.util.TreeSet; public class SortedSetTest { public static void main(String[] args) { SortedSet<Employee> set = new TreeSet<Employee>(); Employee e1 = new Employee(1, "aTestName", "dLastName", 34); Employee e2 = new Employee(2, "nTestName", "pLastName", 30); Employee e3 = new Employee(3, "kTestName", "sLastName", 31); Employee e4 = new Employee(4, "dTestName", "zLastName", 25); set.add(e2); set.add(e3); set.add(e1); set.add(e4); System.out.println(set); } }
Program output:
[Employee : 1 - aTestName - dLastName - 34 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 4 - dTestName - zLastName - 25]
5.1. SortedSet with Comparator
If you want to add some other sorting behavior using Comparator
implementation, you can pass the Comparator
to constructor of sorted collection. e.g.
package corejava.compare; import java.util.SortedSet; import java.util.TreeSet; public class SortedSetTest { public static void main(String[] args) { SortedSet<Employee> set = new TreeSet<Employee>(new FirstNameSorter()); Employee e1 = new Employee(1, "aTestName", "dLastName", 34); Employee e2 = new Employee(2, "nTestName", "pLastName", 30); Employee e3 = new Employee(3, "kTestName", "sLastName", 31); Employee e4 = new Employee(4, "dTestName", "zLastName", 25); set.add(e2); set.add(e3); set.add(e1); set.add(e4); System.out.println(set); } }
Program output:
[Employee : 1 - aTestName - dLastName - 34 , Employee : 2 - nTestName - pLastName - 30 , Employee : 3 - kTestName - sLastName - 31 , Employee : 4 - dTestName - zLastName - 25]
In above code, Comparator
will take precedence and will become default sort order. So easy it is, right??
6. hashCode() and equals()
If you have overridden equals() method in your Employee
class, always remember to honor its behavior.
If two objects are equal using equals()
method then compare()
method should return ‘0‘.
I hope to be clear enough in describing how to sort arraylist of objects. If you still have left with some doubts, leave a comment. I will be happy to resolve.
Happy Learning !!
sujith
Hi,
If we have generic list with different object, how can we sort it
Below is the example…
List list=new ArrayList();
Laptop l1 =new Laptop(1,”Mac”,800)
Laptop l2=new Laptop(2,”dell”,500)
Laptop l3 =new Laptop(3,”acer”,200)
list.add(l1);
list.add(l2);
list.add(l3);
Book b1=new Book(1,”science”,500);
Book b2=new Book(2″science”,600);
Book b3=new Book(3,”science”,700);
list.add(b1);
list.add(b2);
list.add(b3);
I tried implementing compareTo() method in both the entity classes but it does work
Both Laptop and Book has a common variable of price
Can we sort this based on price? if so please help me doing it
Thanks in advance
Sreenivas
I think you need to abstract out the price in a superclass and inherit the Laptop and Book from that. The superclass say Item should inherit from comparable and implement the interface compareTo() method based on the price. Hope this helps.
Prabhat
Hi Lokesh,
I have one Doubt that i have gone through java docs and it has mentioned that “Lists (and arrays) of objects that implement this interface can be sorted automatically by Collections.sort (and Arrays.sort). “.Then let me know is it true that sort() method internally calls compareTo() method or not.How it call internally
Ex:
public class Country implements Comparable{
int countryId;
String countryName;
public Country(int countryId, String countryName) {
super();
this.countryId = countryId;
this.countryName = countryName;
}
@Override
public int compareTo(Country country) {
return (this.countryId country.countryId ) ? 1:0 ;
}
public int getCountryId() {
return countryId;
}
public void setCountryId(int countryId) {
this.countryId = countryId;
}
public String getCountryName() {
return countryName;
}
public void setCountryName(String countryName) {
this.countryName = countryName;
}
}
ComparableMain.java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ComparableMain {
public static void main(String[] args) {
Country indiaCountry=new Country(1, “India”);
Country chinaCountry=new Country(4, “USA”);
Country nepalCountry=new Country(3, “Russia”);
Country bhutanCountry=new Country(2, “Japan”);
List listOfCountries = new ArrayList();
listOfCountries.add(indiaCountry);
listOfCountries.add(usaCountry);
listOfCountries.add(russiaCountry);
listOfCountries.add(japanCountry);
System.out.println(“Before Sort : “);
for (int i = 0; i < listOfCountries.size(); i++) {
Country country=(Country) listOfCountries.get(i);
System.out.println("Country Id: "+country.getCountryId()+"||"+"Country name:"+country.getCountryName());
}
Collections.sort(listOfCountries);
//Here Hoe it call compareTo() internally.
Lokesh Gupta
Collections.sort() internally call Arrays.sort(), which in turn use Arrays.mergeSort(). This
mergeSort()
method usescompareTo()
for comparing elements.madhusmita
nice one.thank you
Chandra
Hi lokesh,
I am getting the following error when I want to override the method of Comparable interface.Can you please help me to know the reason for the error.The below is the source code which I have written.
Error : The method compareTo(Employee) of type Employee must override a superclass method.
public class Employee implements Comparable {
private int empId;
private String empName;
private int age;
private int salary;
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
@Override
public int compareTo(Employee e) {
// TODO Auto-generated method stub
return this.empId-e.empId;
}
@Override
public String toString(){
return “Employee Details: Emp Id: “+empId +” Name: “+empName+” Age: “+age+” Salary: “+salary;
}
}
Thanks and Regards,
Chandra.
Lokesh Gupta
Method is “public int compareTo(Object e)”. Inside method cast the object from object to employee.
OR, declare the class like this: Employee implements Comparable <Employee>
Himansu
Hi Lokesh,
Can you explain more on how to make compare() and compareTo() null safe and its contract with override equal() method.
Regards,
Himansu
Lokesh Gupta
For null handling. refer to this guide.
As per java docs of Comparable interface :
“The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo(e2) == 0 has the same boolean value as e1.equals(e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.”
Himansu
Hi Lokesh,
This is really a gud and lucid explanation but how can we write more null safe compare and compareto method. Entities with null reference or with null fields can slip to this method breaking the code.
Regards,
Himansu
heena
in your example for comparable, how Collections class know that it need to sort on the basis of id only
Lokesh Gupta
Here I have mentioned it.
@Override
public int compareTo(Employee o) {
return this.id - o.id;
}
vidya
Thank you very much….now i got clear information about when to use comparable and comparator
Maddy
Thanks for your nice text, but I have seen one good article on same topic. If anyone interested on same can read that here…
Tan
Hi Lokesh,
I know Comparable & Comparator interface, it is using for sorting objects. But i have some confusion in these 2 Interface when i use comparable & Comparator…?
Lokesh Gupta
Use Comparable if you want to implement default sorting. e.g. Employees will be sort based on their employee ids. Comparator should be used when you are adding multiple ways of sorting or sorting on uncommon fields. e.g. sorting based on Lastname or emaployee age.
Tan
Thx Lokesh. Really it’s great job…..
Abhay
Suppose I need to sort based on both fields Lastname AND employee age then? for example flight search Time and Price then how I would proceed?
Lokesh Gupta
Before java 8 solution will be like this if you want to sort first by lastName and then firstName filed:
For java 8 solution, use something like this:
https://howtodoinjava.com/java8/comparator-example-lambda/
nikhil
Thank you so much
Pratap
If you want to sort by any field of an object no need to write different comparators for each of the field, instead create the constructor for comparator and pass the sort field and sort direction and compare method to have code for each of the cases.
Lokesh Gupta
Yes, this is also possible. But it would need to put all such cases/logic in single class. I do not prefer this.
santhanamgc
Please correct the following sentence in your blog 🙂
Comparable interface provides one method compare(Object o) to implement in any class so that two instances of that class can be compared.
from compare(Object o) to int compareTo(T o)
May be that should be a typo 🙂
Lokesh Gupta
Good catch 🙂
Aseem
Hi Lokesh,
Please correct the typo asap. It wil really create confusions.
Lokesh Gupta
Done
Prudhvi raj
Is there any way to sort the objects with the Id’s in middle out fashion ,say objects with ids 1,2,3,4,5 are in order.I want to sort the order in the following manner 3 ,4,2,5,1
Thank you.
Lokesh Gupta
Raj, Its really interesting logic but I don’t have any specific logic in mind right now. May be I will try to find something. If you get it working, please share.
Tony
Hi Raj
It’s really nice to heard your question.But in normal we are having two types of sorting i.e. Asc./Desc. But per your requirement You are looking something extra than these two.So if You find any solution Please share with us.
veena
// Sorting user-defined object in TreeSet based on id, name
import java.util.*;
class Stud
{
int id;
String name;
Stud(int id, String name)
{
this.id=id;
this.name=name;
}
public String toString()
{
return id + ” ” + name;
}
}
class Studnames implements Comparator
{
public int compare(Stud s1, Stud s2)
{
return s1.name.compareTo(s2.name);
}
}
class Studid implements Comparator
{
public int compare(Stud s1, Stud s2)
{
if(s1.id>s2.id)
{
return 0;
}
else if(s1.id>s2.id)
{
return -1;
}
else
{
return -1;
}
}
}
public class Al
{
public static void main(String args[])
{
SortedSet st = new TreeSet( new Studnames());
st.add(new Stud(100,”amritsar”));
st.add(new Stud(21,”bangalore”));
st.add(new Stud(212,”orrisa”));
st.add(new Stud(213,”mumbai”));
System.out.println(“Sorting by names”);
System.out.println(st);
System.out.println(” “);
System.out.println(“Sorting by id”);
SortedSet st1 = new TreeSet( new Studid());
st1.add(new Stud(101,”amritsar”));
st1.add(new Stud(221,”bangalore”));
st1.add(new Stud(124,”orrisa”));
st1.add(new Stud(121,”mumbai”));
System.out.println(st1);
}
}
1. Have look at the above code
2. Have used TreeSet to sort user defined objects based on id and names.
3. OUTPUT:
Sorting by names
[100 amritsar, 21 bangalore, 213 o, 212 orrisa]
Sorting by id
[101 amritsar]
4. why id’s not getting sorted only one id is getting displayed?
Lokesh Gupta
Correct compare method for class Studid implements Comparator is:
public int compare(Stud s1, Stud s2)
{
if (s1.id > s2.id) {
return 1;
} else if (s1.id < s2.id) { return -1; } else { return 0; } }Use above method and you will get correct output:Sorting by names [100 amritsar, 21 bangalore, 213 mumbai, 212 orrisa] Sorting by id [101 amritsar, 121 mumbai, 124 orrisa, 221 bangalore]
Lucky
Is there any way to sort the objects with the Id’s and Names ,say objects with ids 1,1,2,2 and Names with A,B,A,B.I want to sort the order in the following manner 1,1,A,A,2,2,B,B.
Lokesh Gupta
If I will be in your place, then I will d this kind of sorting at database later while executing SELECT query. No need to put complex things in application, if desired result is easily achievable through one group by and one sort column in SELECT.