Both are interfaces. Comparable is from java.lang where as
Comparator is from java.util packages.
A Comparable object is capable of comparing itself with
another object. The class itself must implement the Comparable interface in
order to be able to compare its instances.
A
Comparator object is capable of comparing two different objects. The class is
not comparing its instances, but some other class’s instances. Hence, the class
in which this comparison is made must implement Comparator interface. However,
this can be tweaked not to implement this interface when used in same class.
If there is a natural or default way of sorting objects then
use Comparable.
If an object can be sorted on multiple ways and client is
specifying on which parameter sorting should take place then use Comparator.
Usually if you are not the author of a class, you wouldn’t have access to use
Comparable so, the only option is to use Comparator.
Let’s
see how we can sort primitive types or object array and list with a simple
program.
PrimitiveSort.java
package com.javaoracleadf.sorting;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class PrimitiveSort {
public static void main(String[] args) {
//sort int array
int[] intArr = {4,8,2,9};
Arrays.sort(intArr);
System.out.println(Arrays.toString(intArr));
//sorting String array
String[] strArr = {"A", "C", "B", "Z", "E"};
Arrays.sort(strArr);
System.out.println(Arrays.toString(strArr));
//sorting list of objects of Wrapper classes
List strList = new ArrayList();
strList.add("A");
strList.add("C");
strList.add("B");
strList.add("Z");
strList.add("E");
Collections.sort(strList);
for(String str: strList) System.out.print(" "+str);
}
}
Output of the above program is:
[2, 4, 8, 9]
[A, B, C, E, Z]
A B C E Z
Now
let’s try to sort an array of a custom class we have.
Employee.java
package com.javaoracleadf.sorting;
public class 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;
}
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" + this.salary + "]";
}
}
Here is the code I used to sort the array of Employee objects.
//sorting custom object array
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Manoj", 25, 10000);
empArr[1] = new Employee(20, "Anand", 29, 20000);
empArr[2] = new Employee(5, "Lakshmi", 35, 5000);
empArr[3] = new Employee(1, "Pavan", 32, 50000);
//sorting employees array using Comparable interface implementation
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
When I tried to run this, it throws following runtime exception.
Exception in thread "main" java.lang.ClassCastException: com.javaoracleadf.sorting.Employee cannot be cast to java.lang.Comparable
at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:290)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:157)
at java.util.ComparableTimSort.sort(ComparableTimSort.java:146)
at java.util.Arrays.sort(Arrays.java:472)
at com.javaoracleadf.sorting.JavaSorting.main(JavaSorting.java:41)
If you want to use Arrays or Collections sorting methods,
your custom class should implement the Comparable interface. Also, you should
override the method compareTo(T obj) in such a way that it returns a negative
integer, zero, or a positive integer if “this” object is less than, equal, or
greater than the object passed as an argument. After
implementing Comparable interface, resulting Employee.java file look like below.
Employee.java
package com.javaoracleadf.sorting;
import java.util.Comparator;
public class Employee implements Comparable {
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) {
//let's sort the employee based on id in ascending order
//returns a negative integer, zero, or a positive integer as this employee id
//is less than, equal to, or greater than the specified object.
return (this.id - emp.id);
}
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" + this.salary + "]";
}
}
If I execute the above sorting logic, it sorts the objects like below.
Default Sorting of Employees list:
[[id=1, name=Pavan, age=32, salary=50000], [id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000]]
As you can see that Employees objects array is sorted by id
in ascending order.
But, in the other scenarios, sorting is needed based on
different parameters. For example, as a manager, he would like to sort the
employees based on Salary. As a HR, he would like to sort them based on the
age. In this situation, using Comparator interface is the best fit because Comparable.compareTo(Object
o) method can sort based on one field only and we can’t chose the
field on which we want to sort the Object.
Comparator interface’s compare(Object o1, Object o2) method
need to be implemented which takes two Object arguments and it should be
implemented in such a way that it returns negative integer if first argument is
less than the second one and returns zero if they are equal and positive integer
if first argument is greater than second one.
After
implementing Comparator’s methods, resulting Employee.java file look like
below.
package com.javaoracleadf.sorting;
import java.util.Comparator;
public class Employee implements Comparable {
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) {
//let's sort the employee based on id in ascending order
//returns a negative integer, zero, or a positive integer as this employee id
//is less than, equal to, or greater than the specified object.
return (this.id - emp.id);
}
public String toString() {
return "[id=" + this.id + ", name=" + this.name + ", age=" + this.age + ", salary=" + this.salary + "]";
}
/**
* Comparator to sort employees list or array in order of Salary
*/
public static Comparator SalaryComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return (int) (e1.getSalary() - e2.getSalary());
}
};
/**
* Comparator to sort employees list or array in order of Age
*/
public static Comparator AgeComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getAge() - e2.getAge();
}
};
/**
* Comparator to sort employees list or array in order of Name
*/
public static Comparator NameComparator = new Comparator() {
@Override
public int compare(Employee e1, Employee e2) {
return e1.getName().compareTo(e2.getName());
}
};
}
We can use these comparators to pass as argument to sort function of Arrays and Collections classes.
//sort employees array using Comparator by Salary
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//sort employees array using Comparator by Age
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//sort employees array using Comparator by Name
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
Here is the output of the above code snippet:
Employees list sorted by Salary:
[[id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000], [id=1, name=Pavan, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000], [id=1, name=Pavan, age=32, salary=50000], [id=5, name=Lakshmi, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Anand, age=29, salary=20000], [id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=1, name=Pavan, age=32, salary=50000]]
We can also create separate class that implements Comparator interface and then use it.
EmployeeComparatorByIdAndName.java
package com.javaoracleadf.sorting;
import java.util.Comparator;
public class EmployeeComparatorByIdAndName implements Comparator {
@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;
}
}
test class where we are using different ways to sort Objects in java.
package com.javaoracleadf.sorting;
import java.util.Arrays;
public class JavaObjectSorting {
/**
* This class shows how to sort custom objects array/list
* implementing Comparable and Comparator interfaces
* @param args
*/
public static void main(String[] args) {
//sorting custom object array
Employee[] empArr = new Employee[4];
empArr[0] = new Employee(10, "Manoj", 25, 10000);
empArr[1] = new Employee(20, "Anand", 29, 20000);
empArr[2] = new Employee(5, "Lakshmi", 35, 5000);
empArr[3] = new Employee(1, "Pavan", 32, 50000);
//sorting employees array using Comparable interface implementation
Arrays.sort(empArr);
System.out.println("Default Sorting of Employees list:\n"+Arrays.toString(empArr));
//sort employees array using Comparator by Salary
Arrays.sort(empArr, Employee.SalaryComparator);
System.out.println("Employees list sorted by Salary:\n"+Arrays.toString(empArr));
//sort employees array using Comparator by Age
Arrays.sort(empArr, Employee.AgeComparator);
System.out.println("Employees list sorted by Age:\n"+Arrays.toString(empArr));
//sort employees array using Comparator by Name
Arrays.sort(empArr, Employee.NameComparator);
System.out.println("Employees list sorted by Name:\n"+Arrays.toString(empArr));
//Employees list sorted by ID and then name using Comparator class
empArr[0] = new Employee(1, "Manoj", 25, 10000);
Arrays.sort(empArr, new EmployeeComparatorByIdAndName());
System.out.println("Employees list sorted by ID and Name:\n"+Arrays.toString(empArr));
}
}
Here is the output of the above program:
Default Sorting of Employees list:
[[id=1, name=Pavan, age=32, salary=50000], [id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000]]
Employees list sorted by Salary:
[[id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000], [id=1, name=Pavan, age=32, salary=50000]]
Employees list sorted by Age:
[[id=10, name=Manoj, age=25, salary=10000], [id=20, name=Anand, age=29, salary=20000], [id=1, name=Pavan, age=32, salary=50000], [id=5, name=Lakshmi, age=35, salary=5000]]
Employees list sorted by Name:
[[id=20, name=Anand, age=29, salary=20000], [id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000], [id=1, name=Pavan, age=32, salary=50000]]
Employees list sorted by ID and Name:
[[id=1, name=Manoj, age=25, salary=10000], [id=1, name=Pavan, age=32, salary=50000], [id=5, name=Lakshmi, age=35, salary=5000], [id=10, name=Manoj, age=25, salary=10000]]