Comparable and Comparator Interface - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Thursday, August 4, 2016

Comparable and Comparator Interface

Comparable and Comparator provide ways to sort the collection of objects. Java provides inbuilt method to sort primitive types array, wrapper classes array or list and array of objects of user defined classes. Here we will learn how to sort an array of primitive type, wrapper classes , String class and then using comparator and comparable interface to sort array, list of user defined classes.

We will use static method's sort of Arrays class to sort array of primitive types and String class. Arrays class available in java.util package.

Let's see example to sort an array of primitive types , String class or Object Array and list of wrapper class' objects and String class' objects.

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * This class shows how to sort array of primitive types, array of objects of
 * wrapper classes, and array of objects of String class.
 *
 */
public class JavaSorting {

 public static void main(String[] args) {
  // sort array of primitive types, like int, char, double etc
  int arr[] = new int[] { 30, 50, 10, 20, 40, 60 };
  Arrays.sort(arr);
  System.out.println("Sorted array of primitive types");
  for (int i = 0; i < arr.length; i++)
   System.out.print(arr[i] + " ");

  // sort an array of objects of String class
  String string[] = new String[] { "xyz", "abc", "fgh", "ret", "qwe" };
  Arrays.sort(string);
  System.out.println("\n\nSorted array of objects of String class");
  for (int i = 0; i < string.length; i++)
   System.out.print(string[i] + " ");

  // sort list of objects of wrapper class
  List<Integer> integersList = new ArrayList<Integer>();
  integersList.add(Integer.valueOf(100));
  integersList.add(Integer.valueOf(50));
  integersList.add(Integer.valueOf(60));
  integersList.add(Integer.valueOf(90));

  Collections.sort(integersList);
  System.out.println("\n\nsorted list of objects of wrapper class");
  for (Integer intValue : integersList)
   System.out.print(intValue + " ");

  // sort list of objects of String class
  List<String> strList = new ArrayList<String>();
  strList.add("H");
  strList.add("K");
  strList.add("A");
  strList.add("J");
  strList.add("I");
  Collections.sort(strList);
  System.out.println("\n\nsorted list of objects of String class");
  for (String str : strList)
   System.out.print(str + " ");
 }
}

Output of above program is shown below

Sorted array of primitive types:
10 20 30 40 50 60

Sorted array of objects of String class:
abc fgh qwe ret xyz

sorted list of objects of wrapper class
50 60 90 100

sorted list of objects of String class
A H I J K

Now we try to run an array of objects of user defined class.

package com.walkingtechie.sort;

import java.util.Arrays;

/**
 * This class shows when we try to sort an array of objects without class
 * implementing java.lang.Comparable interface it throws runtime exception
 */
public class Student {
 String name;
 int rollNo;
 String department;

 public Student(String name, int rollNo, String department) {
  this.name = name;
  this.rollNo = rollNo;
  this.department = department;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getRollNo() {
  return rollNo;
 }

 public void setRollNo(int rollNo) {
  this.rollNo = rollNo;
 }

 public String getDepartment() {
  return department;
 }

 public void setDepartment(String department) {
  this.department = department;
 }

 // toString() method overridden here to print details about Student
 @Override
 public String toString() {
  return "[Name=" + this.name + ", Roll No=" + this.rollNo
    + ", Department=" + this.department + "]";
 }

 public static void main(String[] args) {
  // created an array of objects of Student class
  Student student[] = new Student[5];
  student[0] = new Student("Justin", 101, "Finance");
  student[1] = new Student("James", 102, "HR");
  student[2] = new Student("Santosh", 103, "Sales");
  student[3] = new Student("Richa", 104, "IT");
  student[4] = new Student("Karan", 105, "Manufacturing");
  Arrays.sort(student);
  for (int i = 0; i < student.length; i++)
   System.out.println(student[i]);
 }
}

when try to run above code, it will throw following runtime exception.

Exception in thread "main" java.lang.ClassCastException: com.walkingtechie.sort.Student cannot be cast to java.lang.Comparable
 at java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
 at java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
 at java.util.Arrays.sort(Arrays.java:1246)
 at com.walkingtechie.sort.Student.main(Student.java:59)

All wrapper classes and String class have implemented the java.lang.Comparable interface. Java provides two interface to sort objects using data member of the class.

  1. java.lang.Comparable
  2. java.util.Comparator

Comparable Interface

Java provides Comparable interface which should be implemented by the user defined class,if we want to sort an array and list of objects, comparable interface provide natural order of sorting, and have only one compareTo(T obj) method which is use to sort objects. This method should return negative, zero, and positive value if this object less than, equal to, greater than object passed as argument. Comparable interface belong to java.lang package.

Now Student class have implemented Comparable interface, sorting objects of student based on name in lexicographical order.

package com.walkingtechie.sort;

import java.util.Arrays;

public class Student implements Comparable<Student> {
 String name;
 int rollNo;
 String department;

 public Student(String name, int rollNo, String department) {
  this.name = name;
  this.rollNo = rollNo;
  this.department = department;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getRollNo() {
  return rollNo;
 }

 public void setRollNo(int rollNo) {
  this.rollNo = rollNo;
 }

 public String getDepartment() {
  return department;
 }

 public void setDepartment(String department) {
  this.department = department;
 }

 // toString() method overridden here to print details about Student
 @Override
 public String toString() {
  return "[Name=" + this.name + ", Roll No=" + this.rollNo
    + ", Department=" + this.department + "]";
 }

 // sort Student class based on name data member
 @Override
 public int compareTo(Student o) {
  return this.getName().compareTo(o.getName());
 }

 public static void main(String[] args) {
  Student student[] = new Student[5];
  student[0] = new Student("Justin", 101, "Finance");
  student[1] = new Student("James", 102, "HR");
  student[2] = new Student("Santosh", 103, "Sales");
  student[3] = new Student("Richa", 104, "IT");
  student[4] = new Student("Karan", 105, "Manufacturing");
  Arrays.sort(student);
  for (int i = 0; i < student.length; i++)
   System.out.println(student[i]);
 }
}

Output of above program is shown below

[Name=James, Roll No=102, Department=HR]
[Name=Justin, Roll No=101, Department=Finance]
[Name=Karan, Roll No=105, Department=Manufacturing]
[Name=Richa, Roll No=104, Department=IT]
[Name=Santosh, Roll No=103, Department=Sales]

problem with the Comparable interface is that we have to modify the class, it will give only one kind of sorting.In real world scenario, we want to sort an objects based on different parameters.Like in above example i want to sort student objects based on department parameter, or rollNo parameter. In this situation, we would use Comparator interface of java.util package.

Comparator Interface

Unlike Comparable, Comparator interface separate the class from other class, it does not modify the original class, it gives multiple kind of sorting based on data member of class.

Comparator interface have compare(T obj1, T obj2) method, need to be implemented in such a way that it returns negative, zero, and positive if first parameter less than, equal to, and greater than to second parameter.

Step 1

package com.walkingtechie.comparator.sort;

public class Student {
 String name;
 int rollNo;
 String department;

 public Student(String name, int rollNo, String department) {
  this.name = name;
  this.rollNo = rollNo;
  this.department = department;
 }

 public String getName() {
  return name;
 }

 public void setName(String name) {
  this.name = name;
 }

 public int getRollNo() {
  return rollNo;
 }

 public void setRollNo(int rollNo) {
  this.rollNo = rollNo;
 }

 public String getDepartment() {
  return department;
 }

 public void setDepartment(String department) {
  this.department = department;
 }

 // toString() method overridden here to print details about Student
 @Override
 public String toString() {
  return "[Name=" + this.name + ", Roll No=" + this.rollNo
    + ", Department=" + this.department + "]";
 }
}

Step 2

We will create multiple class for different kind of sorting based on instance variable of class implementing Comparator interface.

package com.walkingtechie.comparator.sort;

import java.util.Comparator;

/* comparator to sort students list or array in order of name
 *
 */
public class NameCompare implements Comparator<Student> {

 @Override
 public int compare(Student o1, Student o2) {
  return o1.getName().compareTo(o2.getName());
 }
}
package com.walkingtechie.comparator.sort;

import java.util.Comparator;

/* comparator to sort students list or array in order of Department
 *
 */
public class DepartmentCompare implements Comparator<Student> {

 @Override
 public int compare(Student o1, Student o2) {

  return o1.getDepartment().compareTo(o2.getDepartment());
 }
}
package com.walkingtechie.comparator.sort;

import java.util.Comparator;

/* comparator to sort students list or array in order of rollNo
 *
 */
public class RollNoComapare implements Comparator<Student> {

 @Override
 public int compare(Student o1, Student o2) {
  return o1.getRollNo() - o2.getRollNo();
 }
}

Step 3

We will use these comparator to pass as argument to sort function of Arrays or Collections class to sort array or List accordingly.

package com.walkingtechie.comparator.sort;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

public class StudentSorting {

 public static void main(String[] args) {
  // created an array of objects of Student class
  Student student[] = new Student[5];
  student[0] = new Student("Justin", 101, "Finance");
  student[1] = new Student("James", 102, "HR");
  student[2] = new Student("Santosh", 103, "Sales");
  student[3] = new Student("Richa", 104, "IT");
  student[4] = new Student("Karan", 105, "Manufacturing");

  // sort an array of objects of Student based on name
  Arrays.sort(student, new NameCompare());
  System.out.println("Student objects sorted by name:");
  for (int i = 0; i < student.length; i++)
   System.out.println(student[i]);
  System.out.println();

  // sort an array of objects of student based on department
  Arrays.sort(student, new DepartmentCompare());
  System.out.println("Student objects sorted by department:");
  for (int i = 0; i < student.length; i++)
   System.out.println(student[i]);
  System.out.println();

  // create a list of student's objects
  List<Student> studentList = new LinkedList<Student>();
  studentList.add(new Student("Richa", 104, "IT"));
  studentList.add(new Student("James", 102, "HR"));
  studentList.add(new Student("Karan", 105, "Manufacturing"));
  studentList.add(new Student("Justin", 101, "Finance"));
  studentList.add(new Student("Santosh", 103, "Sales"));

  // sort an list of objects of student based on rollNo
  Collections.sort(studentList, new RollNoComapare());
  System.out.println("List of Student objects sorted by rollNo:");
  for (Student student2 : studentList)
   System.out.println(student2);
 }
}

Output of above program is shown below

Student objects sorted by name:
[Name=James, Roll No=102, Department=HR]
[Name=Justin, Roll No=101, Department=Finance]
[Name=Karan, Roll No=105, Department=Manufacturing]
[Name=Richa, Roll No=104, Department=IT]
[Name=Santosh, Roll No=103, Department=Sales]

Student objects sorted by department:
[Name=Justin, Roll No=101, Department=Finance]
[Name=James, Roll No=102, Department=HR]
[Name=Richa, Roll No=104, Department=IT]
[Name=Karan, Roll No=105, Department=Manufacturing]
[Name=Santosh, Roll No=103, Department=Sales]

List of Student objects sorted by rollNo:
[Name=Justin, Roll No=101, Department=Finance]
[Name=James, Roll No=102, Department=HR]
[Name=Santosh, Roll No=103, Department=Sales]
[Name=Richa, Roll No=104, Department=IT]
[Name=Karan, Roll No=105, Department=Manufacturing]

Difference between Comparable and Comparator interface.

Comparable Comparator
Comparable interface can be used to provide single way of sorting. Comparator interface can be used to provide multiple ways of sorting.
Comparable, class need to implement it, means it modified the class. Using Comparator, we don't need to modify the actual class.
Comparable interface available in java.lang package. Comparator interface available in java.util package.
Comparable interface provides compareTo(T obj) method. Comparator interface provides compare(T obj1, T obj2) method.
Sort list and array of Comparable interface type by using Collections.sort(List) and Arrays.sort(arr) accordingly. Sort list and array of Comparator interface type by using Collections.sort(List,Comparator) and Arrays.sort(arr,Comparator) accordingly.

To summarize, if sorting of objects needs to be based on natural order then use Comparable whereas if you sorting needs to be done on attributes of different objects, then use Comparator in Java.

1 comment :

  1. Good work keep it up. Thanks for giving such a nice explanation.

    ReplyDelete