Java interview questions comparable and comparator

Hey, Tea Lovers! Today let’s look at the most asked interview question, Comparable vs Comparator. Both beginners and experienced persons get this question in their interviews. This post is one of the many in the series of Interview Questions, where we don’t just hang you with one line answer, rather try to explain it so that it gets fit into your head.


You can follow me on social media via @coderstea on Twitter, Linkedin, Facebook, or Instagram. We also share high-quality videos about programming on our Youtube channel. You can also publish your post on CodersTea, just share your thought on Contact Us or let us know in the comments.

I know you are in a hurry to prepare for the interview, so I will make this post as short as possible, So prepare your cup of tea to sip and code.

Why We use Comparator or Comparable

First, we need to understand why comparable & comparator comes into the picture. They give you the answer of comparison. Like, which one is greater which one is smaller. And the main reason for doing that is to Sort the collection of objects. We can easily compare the Integer or String naturally, but the complex or regular POJO object has multiple fields. In that case, we need to specify how we are determining which objects should come first or which one is greater.

In java String and Wrapper classes had implemented the Comparable interface. So if you store string or wrapper class objects then it will be used Comparable & get Sorted.

Sorting

Sorting is any process of arranging items systematically. Comparable and Comparator interfaces use Generics for compile-time type checking.
Collections class provides static methods for sorting the elements of a collection. If collection elements are of a Set type, we can use TreeSet. However, we cannot sort the elements of the List. Collections class provides methods for sorting the elements of List type elements.

Example of Sorting

Let understand with a coding example, First, we will sort int, String & List then after we create one custom Student class and try to understand what was the issue. The full source code can be found on GitHub.

Code

//Primitive Data-type Integer Array sort
int[] intArray = {8, 1, 10, 2};
out.println("Primitive Data-type Integer Array Before sort : " + Arrays.toString(intArray));
Arrays.sort(intArray);
out.println("Primitive Data-type Integer Array After sort : " + Arrays.toString(intArray) + "\n");
//In-build Class String Array sort
String[] strArray = {"C", "O", "D", "E", "R", "S", "T", "E", "A"};
out.println("In-build Class String Array Before sort : " + Arrays.toString(strArray));
Arrays.sort(strArray);
out.println("In-build Class String Array After sort : " + Arrays.toString(strArray) + "\n");
//List Collection of String type sort
List<String> listOfStringType = new ArrayList<>(Arrays.asList("C", "O", "D", "E", "R", "S", "T", "E", "A"));
out.println("List Collection of String type Before sort : " + listOfStringType.stream().collect(Collectors.joining(", ")));
Collections.sort(listOfStringType); //Sorting From Collection Class as Mentioned Above
out.println("List Collection of String type After sort : " + listOfStringType.stream().collect(Collectors.joining(", ")));

Output

Primitive Data-type Integer Array Before sort : [8, 1, 10, 2]
Primitive Data-type Integer Array After sort : [1, 2, 8, 10]
In-build Class String Array Before sort : [C, O, D, E, R, S, T, E, A]
In-build Class String Array After sort : [A, C, D, E, E, O, R, S, T]
List Collection of String type Before sort : C, O, D, E, R, S, T, E, A
List Collection of String type After sort : A, C, D, E, E, O, R, S, T

As above console output, we can see that with java inbuild primitive & wrapper class the sorting working properly, let see the same with a custom class.

Custom class Code example.

Code

class Student {
    private int rollNo;
    private String name;
    private int classNo;
    private String divison;
    // constructor, getters, and setters
}
public static void compareAndSortStudentsWithoutComparisionLogic() {
    Student[] studentArray = new Student[4];
    studentArray[0] = new Student(3, "Veronika", 10, "C");
    studentArray[1] = new Student(1, "Sym", 8, "D");
    studentArray[2] = new Student(31, "Mahesh", 11, "B");
    studentArray[3] = new Student(2, "Imran", 9, "A");
    out.print("Custom Student Class Array Before sort : ");
    Stream.of(studentArray).forEach(e -> out.print(e.getRollNo() + " "));
    Arrays.sort(studentArray);
    out.print("\nCustom Student Class Array After sort : ");
    Stream.of(studentArray).forEach(e -> out.print(e.getRollNo() + " "));
}

Output

Custom Student Class Array Before sort : 3 1 31 2 Exception in thread "main" java.lang.ClassCastException: class sd.sym.initiative.interview.collection.Student cannot be cast to class java.lang.Comparable (sd.sym.initiative.interview.collection.Student is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap')
	at java.base/java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320)
	at java.base/java.util.ComparableTimSort.sort(ComparableTimSort.java:188)
	at java.base/java.util.Arrays.sort(Arrays.java:1249)
	at sd.sym.initiative.interview.collection.SortStudentClass.main(SortStudentClass.java:75)

Here is a problem, When you try to run this, it throws the runtime exception as the Student class cannot be cast to class java.lang.Comparable. Because when JVM tried to sort custom class, it starts the search the logic for comparing this custom class. Since you didn’t define any, it throws the Exception.

Now let us look at the ways to implement this logic.

Comparable

A Comparable interface in java.lang package is used to order the objects of the user-defined class. It contains only one method named compareTo(Object object)

A Comparable object is capable of comparing itself with another object.

It provides a single comparison only, meaning all comparisons are tied to one specific logic only. You can’t scale with multiple sorting methods depending on the requirement.

MethodDescription
public int compareTo(Object object) Compares this object with the specified object for order & return,

a positive integer, if the current object is greater than the specified object.

a negative integer, if the current object is less than the specified object.

zero, if the current object is equal to the specified object.

Comparable Method

Let’s simply use the previous example with this logic and avoid that annoying error.

Code

The full source code can be found on GitHub.

class Student2 implements Comparable<Student2> {
    private int rollNo;
    private String name;
    private int classNo;
    private String divison;
    @Override
    // the comparisons between this and the another Student2 Object
    public int compareTo(Student2 anotherStudent2) {
        return (Integer.compare(this.rollNo, anotherStudent2.getRollNo()));
    }
   // getters. setters,constructor
}
public static void sortWithComparableOnStudent2() {
    Student2[] student2Array = new Student2[4];
    student2Array[0] = new Student2(3, "Veronika", 10, "C");
    student2Array[1] = new Student2(1, "Sym", 8, "D");
    student2Array[2] = new Student2(31, "Mahesh", 11, "B");
    student2Array[3] = new Student2(2, "Imran", 9, "A");
    out.print("Custom Student Class Array Before sort : ");
    Stream.of(student2Array).forEach(e -> out.print(e.getRollNo() +" "));
    Arrays.sort(student2Array);
    out.print("\nCustom Student Class Array After sort : ");
    Stream.of(student2Array).forEach(e -> out.print(e.getRollNo() +" "));
    //Using Collections Class
    List<Student2> studentList = new ArrayList<>();
    studentList.add(new Student2(3, "Veronika", 10, "C"));
    studentList.add(new Student2(31, "Mahesh", 11, "B"));
    studentList.add(new Student2(2, "Imran", 10, "A"));
    studentList.add(new Student2(1, "Sym", 8, "D"));
    studentList.add(new Student2());
    studentList.add(new Student2());
    out.print("\n\nCustom Student Class list Before sort : ");
    studentList.forEach(e -> out.print(e.getRollNo() +" "));
    //Sort List as per mentioned logic in comparator
    Collections.sort(studentList);
    out.print("\nCustom Student Class list After sort : ");
    studentList.forEach(e -> out.print(e.getRollNo() +" "));
    //Sort List in reverse as per mentioned logic in comparator
    Collections.sort(studentList, Comparator.reverseOrder());
    out.print("\nCustom Student Class list After reverse sort : ");
    studentList.forEach(e -> out.print(e.getRollNo() +" "));
}

Output

Custom Student Class Array Before sort : 3 1 31 2
Custom Student Class Array After sort : 1 2 3 31
Custom Student Class list Before sort : 3 31 2 1 0 0
Custom Student Class list After sort : 0 0 1 2 3 31
Custom Student Class list After reverse sort : 31 3 2 1 0 0 

Comparator

A Comparator interface is used to order the objects of a user-defined class.

This interface is under java.util package and contains 2 methods compare(Object obj1,Object obj2) and equals(Object element).

The biggest advantage of the Comparator is that it is pluggable. With this, unlike Comparable, you have the flexibility to add as much comparison logic as you want. Simply create an object by implementing a Comparator and passing it to the sorting method. And since Java 8’s lambda showed up, a one-liner is all you need.

The Comparator interface has many methods, the below are required frequently. to get a full list click here.

MethodDescription
public int compare(Object obj1, Object obj2) Compares its two arguments for order.
public boolean equals(Object obj) Indicates whether some other object is “equal to” this comparator
Comparator methods

Let’s simply use the previous example with this logic and avoid that annoying error.

Code

class StudentRollNoComparator implements Comparator<Student> {
	@Override
	public int compare(Student student0, Student student1) {
		int studentRollno0 = student0.getRollNo();
		int studentRollno1 = student1.getRollNo();
		return (studentRollno0 == studentRollno1 ? 0 : studentRollno0 < studentRollno1 ? -1 : 1 );
	}
}
public static void compareAndSortOnComparator() {
    //Using Collections Class
    List<Student> studentList = new ArrayList<>();
    studentList.add(new Student(3, "Veronika", 10, "C"));
    studentList.add(new Student(31, "Mahesh", 11, "B"));
    studentList.add(new Student(2, "Imran", 10, "A"));
    studentList.add(new Student(1, "Sym", 8, "D"));
    out.print("\nCustom Student Class list Before sort : ");
    studentList.forEach(out::print);
    //--------- Sorting base on RollNo From StudentRollNoComparable class mentioned logic in comparator
    StudentRollNoComparator studentRollNoComparator = new StudentRollNoComparator();
    Collections.sort(studentList, studentRollNoComparator);
    out.print("\n\nCustom Student Class list based on rollNo After sort : ");
    studentList.forEach(e -> out.print(e.getRollNo() +" "));
    //In Reverse Order
    Collections.sort(studentList, studentRollNoComparator.reversed());
    out.print("\nCustom Student Class list based on rollNo After reversed sort  : ");
    studentList.forEach(e -> out.print(e.getRollNo() +" "));
    //--------- Sorting base on Name From StudentRollNoComparable class mentioned logic in comparator
    Comparator<Student> studentNameComparator = new Comparator<Student>() {
        @Override
        public int compare(Student student0, Student student1) {
            return student0.getName().compareTo(student1.getName());
        }
    }; // with lambda ====>  (student0, student1) -> student0.getName().compareTo(student1.getName());
    Collections.sort(studentList, studentNameComparator);
    out.print("\n\nCustom Student Class list based on name After sort : ");
    studentList.forEach(e -> out.print(e.getName() +" "));
    // you can also pass the at runtime without creating the implementation.
    Collections.sort(studentList, (s1, s2) -> s1.getDivison().compareTo(s2.getDivison()));
    out.print("\n\nyou can also pass the at runtime without creating the implementation. ");
    studentList.forEach(e -> out.print(e.getName() +" "));
    // or use the comparators static method
    Collections.sort(studentList, Comparator.comparing(Student::getDivison));
    out.print("\n\nusing comparator's static method ");
    studentList.forEach(e -> out.print(e.getName() +" "));
    Collections.sort(studentList, studentNameComparator.reversed());
    out.print("\nCustom Student Class list based on name After reversed sort : ");
    studentList.forEach(e -> out.print(e.getName() +" "));
}

Output

Custom Student Class list Before sort : Student [rollNo=3, name=Veronika, classNo=10, divison=C]Student [rollNo=31, name=Mahesh, classNo=11, divison=B]Student [rollNo=2, name=Imran, classNo=10, divison=A]Student [rollNo=1, name=Sym, classNo=8, divison=D]
Custom Student Class list based on rollNo After sort : 1 2 3 31
Custom Student Class list based on rollNo After reversed sort  : 31 3 2 1
Custom Student Class list based on name After sort : Imran Mahesh Sym Veronika
you can also pass the at runtime without creating the implementation. Imran Mahesh Veronika Sym
using comparator's static method Imran Mahesh Veronika Sym
Custom Student Class list based on name After reversed sort : Veronika Sym Mahesh Imran 

Difference between Comparable and Comparator

Sr. No ComparableComparator
1 Comparable provides a single sorting sequence. In other words, we can sort the collection based on a single element such as rollno, name. The Comparator provides multiple sorting sequences. In other words, we can sort the collection based on multiple elements such as rollno, name.
2 Comparable affects the original class, which means the actual class is modified. Comparator doesn’t affect the original class, which means the actual class is not modified.
3 Comparable provides compareTo() method to sort elements. Comparator provides compare() method to sort elements.
4 Comparable is in java.lang package. The comparator is in java.util package.
5 We can sort the list elements of Comparable type by Collections.sort(List) method. We can sort the list elements of Comparator type by the Collections.sort(List, Comparator) method.
Difference between Comparable and Comparator

When to Use What, and Why

Let us look at When to use what, where, and how…

When to Use Comparable

The custom class defined sorting logic, don’t want to modify from end-user & force end-user to use that logic for sorting.

For example, String and Integer and other Wrapper classes, they by-default implement comparable to us the natural comparison of the types. So we don’t need to write logic.

When to Use Comparator

The Comparator provides multiple sorting sequences. In other words, we can sort the collection based on multiple elements such as rollno, name.

Due to this, the Comparator is very useful. It is used widely as it below example you can see that all application is added only due to this feature.

Don’t want to modify source class or
When you cannot have access to the class which you have to mention sorting

In many cases, we are not able to modify the source code to make our comparison. For example, the Integer class already provided a logic but if you want to provide some custom logic for sorting, we can do so with Comparator.

Want to define two or more sorting logic

The best-case scenario for Comparator is when we have different comparison logic for various fields and want to sort something based on requirements.

Conclusion

That’s it for this post. We looked at what is Comparable and Comparator, the differences between them, and many more tips on when and what to use.

This post is one of the many in the series of Interview Questions, where we don’t just hang you with one line answer, rather try to explain it so that it gets fit into your head.

You can learn more about other Java features such as Stream API, Best Practices, Functional Programming.

The full source code can be found on GitHub and the Full project is available here.

Please feel free to suggest any changes, such as additional info, or if you have any questions on some points let us know in the comments. We will be happy to help you.

See you in the next post. HAKUNA MATATA!!!

  • How to Easily use Factory Design Pattern in Java

  • Java Switch Statement is now more Powerful | Java 18

  • What’s new in Java 18? New Features of New Java 18

  • Most Loved Interview Question: How HashMap Works in Java

Related

What is difference between Comparator and comparable in Java?

Comparator in Java is used to sort attributes of different objects. Comparable interface compares “this” reference with the object specified. Comparator in Java compares two different class objects provided. Comparable is present in java.

What is the difference between Comparator vs comparable?

While Comparable is used on objects that are naturally ordered, the Comparator interface implements sorting by taking the attributes of an object into consideration. Further, Comparator sorting takes into account objects of two different classes and Comparable compares objects using the “this” reference.

Can we use both comparable and Comparator in Java?

Yes we can extend any pojo class to implement both comparable and comparator interface and implement the methods defined by them. I implemented it in sample Student POJO class. When called Collections.

Why do we use comparable and Comparator in Java?

Comparable interface can be used to provide single way of sorting whereas Comparator interface is used to provide different ways of sorting. For using Comparable, Class needs to implement it whereas for using Comparator we don't need to make any change in the class. Comparable interface is in java.