Java sort arraylist of objects – Comparable and Comparator example

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 !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

33 thoughts on “Java sort arraylist of objects – Comparable and Comparator example”

  1. 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

    • 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.

      public class MyItem implements Comparable<MyItem>  {
              double price;
      
      	@Override
      	public int compareTo(MyItem o) {
      		return Double.compare(this.getPrice(), o.getPrice());
      	}
      }
      List<MyItem> items = new ArrayList<MyItem>();
      ...
      ...
      Collections.sort(items );
      //This will give output 200, 500, 500, 600, 700, 800
      
      
  2. 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.

    • Collections.sort() internally call Arrays.sort(), which in turn use Arrays.mergeSort(). This mergeSort() method uses compareTo() for comparing elements.

  3. 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.

    • 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>

    • 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.”

  4. 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

  5. in your example for comparable, how Collections class know that it need to sort on the basis of id only

  6. Thanks for your nice text, but I have seen one good article on same topic. If anyone interested on same can read that here…

  7. 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…?

    • 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.

      • 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?

        • Before java 8 solution will be like this if you want to sort first by lastName and then firstName filed:

          import java.util.*;
          
          public class Name implements Comparable&amp;amp;lt;Name&amp;amp;gt; {
              private final String firstName, lastName;
          
             //More code
              public String toString() {
          	return firstName + &amp;amp;quot; &amp;amp;quot; + lastName;
              }
          
              public int compareTo(Name n) {
                  int lastCmp = lastName.compareTo(n.lastName); //First compare by last name
                  return (lastCmp != 0 ? lastCmp : firstName.compareTo(n.firstName)); //If lat name matches then compare by first name
              }
          }
          

          For java 8 solution, use something like this:

          List&amp;amp;lt;Employee&amp;amp;gt; employees  = getEmployees();
           
          //Sorting on multiple fields; Group by.
          Comparator&amp;amp;lt;Employee&amp;amp;gt; groupByComparator = Comparator.comparing(Employee::getFirstName)
                                                              .thenComparing(Employee::getLastName);
          employees.sort(groupByComparator);
          

          https://howtodoinjava.com/java8/comparator-example-lambda/

  8. 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.

  9. 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 🙂

  10. 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.

    • 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.

  11. // 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?

    • 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]

      • 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.

        • 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.

Comments are closed.

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.