Sunday, June 7, 2015

Comparable and Comparator- When and how to use? [Concise]

When there comes the need of sorting objects, be it using Collections.sort() or just adding elements to Treeset etc, java.lang.Comparable and java.util.Comparator come into picture. For default sorting of objects in the collection, we need to implement Comparable and override below method in that class, unless we are using some pre-defined class that already implements Comparable like String, Integer etc.,
int compareTo(T o)
If we want to provide an external sorting logic to override the default one, the class needs to implement Comparator interface and override the following method:
int compare(T o1, T o2)
The question: Why use Comparator when we already have Comparable?
Answer: If you have authored that class, then you can give a default sorting behavior by implementing Comparable and use that logic to sort whenever needed. Now, let's say that you are using an existing class whose source you can not modify and the default sorting logic of which you are not satisfied with. What now? Just write a Comparator using your own sorting process and use that instance to sort. See below sample programs.

The API information is here:
1. java.lang.Comparable
2. Java.util.Comparator
Lets dig into this with our custom class.
package com.blogspot.javabambino.collections;

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

class Student implements Comparable<Student> {
    String name;
    int rollNumber;
    int rank;

    public Student(String name, int rollNumber, int rank) {
        this.name = name;
        this.rollNumber = rollNumber;
        this.rank = rank;
    }

    //default sorting based on rollNumber
    public int compareTo(Student student) {
        return this.rollNumber - student.rollNumber;
    }

    public String toString(){
        return name;
    }
}

public class ComparableAndComparatorTest {
    public static void main(String[] args) {
        Student s1 = new Student("Abhi",1,3);
        Student s2 = new Student("Asha",2,10);
        Student s3 = new Student("Jacky",3,7);
        Student s4 = new Student("Ron",4,10);

        List<Student> students = new ArrayList<Student>();
        students.add(s4);
        students.add(s2);
        students.add(s3);
        students.add(s1);

        System.out.println("Before sorting:");
        System.out.println(students + "\n");

        //1. This uses default comparison, from Students class
        Collections.sort(students);

        System.out.println("Using default sorting (rollnumber):");
        System.out.println(students + "\n");

        //2. Providing a comparator to override default comparison
        Comparator<Student> rankComparator = new Comparator<Student>() {
            @Override
            public int compare(Student stud1, Student stud2) {
                int diff = stud1.rank - stud2.rank;
                if (diff==0)
                    //if rank is same, sort by rollnumber
                    diff = stud1.rollNumber-stud2.rollNumber;
                return diff;
            }
        };

        Collections.sort(students,rankComparator);

        System.out.println("Using overridden sorting logic (rank, then rollnumber): ");
        System.out.println(students);
    }
}
Our input was in following sequence (just for readability):
NameRollnumberRank
Ron410
Asha210
Jacky37
Abhi13

and the output is:

Before sorting:
[Ron, Asha, Jacky, Abhi]

Using default sorting (rollnumber):
[Abhi, Asha, Jacky, Ron]

Using overridden sorting logic (rank, then rollnumber):
[Abhi, Jacky, Asha, Ron]

1 comment:

  1. Good work, This one is the most asked interview topic.

    ReplyDelete

Liked or hated the post? Leave your words of wisdom! Thank you :)