The Comparable and Comparator interfaces allow for easy sorting of user-defined classes. Not all collections allow for direct sorting of elements, unlike TreeSet and TreeMap.

\(\\\)

The Comparable interface

This interface is found in the java.lang package. It is a member of the Java Collections Framework and has only one method:
public int compareTo(Object o).

It is used to sort a sequence of objects with respect to any one attribute of those objects.

Strings and wrapper class objects can also be sorted using the Comparable interface. To use this interface, the class has to of course, implement this interface. However, this is not necessary when it comes to String and Wrapper classes. These implement the Comparable interface by default.

This interface orders the objects of the class implementing this interface in what is called the class’s natural ordering. Since the compareTo() method is implemented in the same class whose objects we have to sort, regular or intuitive ordering is done with this interface.

To sort a list use: Collections.sort(name_of_list)

Example

Let us consider a class Student with attributes : - name: String - id : int

Our goal is to sort an ArrayList of students based on their id number.

import java.util.*;

class Student implements Comparable<Student>
{
	String name;
	int id;
	
	Student(String name, int id)
	{
		this.name = name;
		this.id = id;
	}
	
	@Override
	public int compareTo(Student s)
	{
		if (this.id < s.id)
		{
			return -1;
		}
		
		else if (this.id > s.id)
		{
			return 1;
		}
		
		else
		{
			return 0;
		}
	}
	
	@Override
	public String toString()
	{
		return "Name: " + this.name + " id: " + this.id;
	}
}
public class Test
{
	public static void main(String[] args)
	{
		ArrayList<Student> list = new ArrayList<Student>();
		list.add(new Student("a", 1));
		list.add(new Student("b", 2));
		list.add(new Student("c", 3));
		list.add(new Student("d", 4));
		
		Collections.sort(list);
		
		for (Student x: list)
		{
			System.out.println(x);
		}
	}
}

And the output:

:~$javac Test.java
:~$java -Xmx128M -Xms16M Test
Name: a id: 1
Name: b id: 2
Name: c id: 3
Name: d id: 4

\[\\\]

The Comparator Interface

This interface is located in the java.util package and allows you to compare objects based on several parameters. The class whose objects we are sorting does not have to implement Comparator, as we shall see in the following example.

One can also sort objects of different classes using this interface. But this is not possible directly, though it can be done by making both classes implement a common interface with the common parameter with respect to which the objects will be sorted.

Lets take the same example as above where we sort the students based with respect to their id numbers and then with respect to their names.

The changes to the Student class are few. We of course remove the implements Comparable<Student> line as well as the compareTo() method.

import java.util.*;

class Student
{
	String name;
	int id;
	
	Student(String name, int id)
	{
		this.name = name;
		this.id = id;
	}
	
	
	
	@Override
	public String toString()
	{
		return "Name: " + this.name + " id: " + this.id;
	}
}

Next, we add two classes which allow us to sort Student objects — one for the id sorting and the other for the names.

In the SortByName class, we make use of the default String method compareTo() which saves us a lot of time and effort.

class SortByName implements Comparator<Student>
{
	public int compare(Student a, Student b)
	{
		return (a.name).compareTo(b.name);
	}
}
class SortById implements Comparator<Student>
{
	public int compare(Student a, Student b)
	{
		return a.id - b.id;
	}
}

Now, in the Test class, we pass anonymous instances of the above classes as a second argument to the Collections.sort() method.

public class Test
{
	public static void main(String[] args)
	{
		ArrayList<Student> list = new ArrayList<Student>();
		list.add(new Student("a", 1));
		list.add(new Student("b", 2));
		list.add(new Student("c", 3));
		list.add(new Student("d", 4));
		
		Collections.sort(list, new SortById());
		
		for (Student x: list)
		{
			System.out.println(x);
		}
	}
}

The output:

:~$javac Test.java
:~$java -Xmx128M -Xms16M Test
Name: a id: 1
Name: b id: 2
Name: c id: 3
Name: d id: 4

Let us make this more concise with the use of anonymous classes for the Comparator method of sorting. Instead of writing the SortByName and the SortById classes, we can do this:

public class Test
{
	public static void main(String[] args)
	{
		ArrayList<Student> list = new ArrayList<Student>();
		list.add(new Student("a", 1));
		list.add(new Student("b", 2));
		list.add(new Student("c", 3));
		list.add(new Student("d", 4));
		
		Collections.sort(list, new Comparator<Student>()
		 {
			 public int compare(Student a, Student b)
			 {
				 return a.id - b.id;
			 }	
		 });
		
		for (Student x: list)
		{
			System.out.println(x);
		}
	}
}

The output is exactly the same:

:~$javac Test.java
:~$java -Xmx128M -Xms16M Test
Name: a id: 1
Name: b id: 2
Name: c id: 3
Name: d id: 4