Comparing the two numeric values like two integers or two float values are easy in Java. You just have to use arithmetic operators.
int a = 1;
int b = 5;
if (a > b) {
System.out.println("a is greater than b");
} else {
System.out.println("b is greater than a");
}
Output: b is greater than a
Here we have used the greater than (>) operator to compare two numeric values.
Now, let’s try to create a Student
class and compare the objects of that class using the same approach.
public class Student {
private final int rank;
private final String name;
public Student(int rank, String name) {
this.rank = rank;
this.name = name;
}
public int getRank() {
return rank;
}
public String getName() {
return name;
}
@Override
public String toString() {
return rank + ". " + name;
}
}
Compare two objects of Student class using greater than operator –
Student tom = new Student(1, "Tom");
Student jerry = new Student(5, "Jerry");
if (tom > jerry) {
System.out.println("Tom is better than Jerry");
} else {
System.out.println("Jerry is greater than Tom");
}
You will get a compilation error at the highlighted line stating: The operator > is undefined for the argument type(s) Student, Student
.
The reason for this error is pretty simple. This operator is not applicable for objects. Additionally, Java doesn’t know how to compare two students – is it by name or rank? JVM won’t make the guess and politely throw the compilation error.
Comparable Interface
Now the question is – how to compare two student objects? The answer is, you have to implement the
interface.Comparable
public interface Comparable<T> {
public int compareTo(T o);
}
As you can see, the interface is pretty simple. You just have to override one simple method compareTo(T o)
and return an int
value.
But what value to return? The rule is –
Scenario | Return Vale |
---|---|
Input object (o) is greater | Positive value |
Input object (o) is lesser | Negative value |
Input object (o) is equal | Zero |
In our example, let’s assume, you want to compare by rank. Lesser the rank, better the student. You have to write that inside the compareTo() method and use this method during comparison instead of greater than operator. So, you can rewrite the code as below –
public class Student implements Comparable<Student> {
private final int rank;
private final String name;
public Student(int rank, String name) {
this.rank = rank;
this.name = name;
}
@Override
public int compareTo(Student o) {
return rank - o.getRank();
}
public int getRank() {
return rank;
}
public String getName() {
return name;
}
}
Student tom = new Student(1, "Tom");
Student jerry = new Student(5, "Jerry");
if (tom.compareTo(jerry) < 0) {
System.out.println("Tom is better than Jerry");
} else {
System.out.println("Jerry is greater than Tom");
}
Output: Tom is better than Jerry
As we have seen, the Comparable interface defines the natural or default ordering of the objects of a class. We can even sort a Student collection using the Collectios.sort()
metod.
Student student1 = new Student(1, "Tom");
Student student2 = new Student(5, "Jerry");
Student student3 = new Student(4, "Harry");
Student student4 = new Student(2, "Jack");
Student student5 = new Student(3, "Rose");
List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
Collections.sort(studentList);
System.out.println(studentList);
Output: [1. Tom, 2. Jack, 3. Rose, 4. Harry, 5. Jerry]
When we pass a collection to the Collections.sort() method, objects of that collection are sorted based on their natural order defined by the CompareTo() method.
Limitation with Comparable interface
Using the Comparable interface you can implement only one way of comparison. Let’s assume, you want to sort based on name. You can say – well, change the comparison logic inside compareTo() method. That will in fact work. But what if you want to compare based on both name and rank?
Don’t worry. We can do that as well. Just use the
interface and provide the custom comparison logic as you want.Comparator
Comparator interface
public interface Comparator<T> {
int compare(T o1, T o2);
}
As you can see, the interface is similar to Comparable interface. You just have to override compare()
method and return an int
value.
But what value to return? The rule is similar to compareTo() method –
Scenario | Return Vale |
---|---|
o1 is greater than o2 | Positive value |
o1 is less than o2 | Negative value |
o1 and o2 is equal | Zero |
Let’s first create two implementations of Comparator interface.
public class CompareByName implements Comparator<Student> {
public int compare(Student obj1, Student obj2) {
return obj1.getName().compareTo(obj2.getName());
}
}
public class CompareByRank implements Comparator<Student> {
public int compare(Student obj1, Student obj2) {
return obj2.getRank() - obj2.getRank();
}
}
In collections.sort() method, along with providing the collection, you can also provide a comparator based on which collection will be sorted.
Student student1 = new Student(1, "Tom");
Student student2 = new Student(5, "Jerry");
Student student3 = new Student(4, "Harry");
Student student4 = new Student(2, "Jack");
Student student5 = new Student(3, "Rose");
List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
Collections.sort(studentList);
System.out.println(studentList);
Collections.sort(studentList, new CompareByRank());
System.out.println(studentList);
Collections.sort(studentList, new CompareByName());
System.out.println(studentList);
Output:
[1. Tom, 2. Jack, 3. Rose, 4. Harry, 5. Jerry]
[1. Tom, 2. Jack, 3. Rose, 4. Harry, 5. Jerry]
[4. Harry, 2. Jack, 5. Jerry, 3. Rose, 1. Tom]
Please note, the default sorting order is ascending. You can also sort in descending order using following approach –
Student student1 = new Student(1, "Tom");
Student student2 = new Student(5, "Jerry");
Student student3 = new Student(4, "Harry");
Student student4 = new Student(2, "Jack");
Student student5 = new Student(3, "Rose");
List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
Collections.sort(studentList, Collections.reverseOrder());
System.out.println(studentList);
Collections.sort(studentList, new CompareByName().reversed());
System.out.println(studentList);
Output:
[5. Jerry, 4. Harry, 3. Rose, 2. Jack, 1. Tom]
[1. Tom, 3. Rose, 5. Jerry, 2. Jack, 4. Harry]
TreeSet
TreeSet
is one of the implementations of the Set
interface where elements are ordered based on their natural ordering. You can also provide a Comparator at set creation time for custom sorting.
Student student1 = new Student(1, "Tom");
Student student2 = new Student(5, "Jerry");
Student student3 = new Student(4, "Harry");
Student student4 = new Student(2, "Jack");
Student student5 = new Student(3, "Rose");
List<Student> studentList = Arrays.asList(student1, student2, student3, student4, student5);
Set<Student> studentSet1 = new TreeSet<Student>(studentList);
studentSet1.addAll(studentList);
Set<Student> studentSet2 = new TreeSet<Student>(new CompareByName());
studentSet2.addAll(studentList);
System.out.println(studentSet1);
System.out.println(studentSet2);
Output:
[1. Tom, 2. Jack, 3. Rose, 4. Harry, 5. Jerry]
[4. Harry, 2. Jack, 5. Jerry, 3. Rose, 1. Tom]
TreeMap
TreeMap
is one of the implementations of the Map
interface where elements are ordered based on their natural ordering of its keys. You can also provide a Comparator at Map creation time for custom sorting.
Map<Integer, String> studentMap1 = new TreeMap<Integer, String>();
studentMap1.put(3, "Rose");
studentMap1.put(1, "Tom");
studentMap1.put(2, "Jack");
Map<Integer, String> studentMap2 = new TreeMap<Integer, String>(Collections.reverseOrder());
studentMap2.put(3, "Rose");
studentMap2.put(1, "Tom");
studentMap2.put(2, "Jack");
System.out.println(studentMap1);
System.out.println(studentMap2);
Output:
{1=Tom, 2=Jack, 3=Rose}
{3=Rose, 2=Jack, 1=Tom}
Difference between Comparable and Comparator
As you have already seen, there are few differences between Comparable and Comparator interfaces. I’ll list down the differences below –
Comparable | Comparator |
---|---|
Comparable interface present in java.lang package. | Comparator interface present in java.util package. |
Comparable provides compareTo() method to sort elements. | Comparator provides compare() method to sort elements. |
Comparable provides a single way of sorting. | Comparator can provide multiple ways of sorting. |
Comparable provides natural sorting order. | Comparator provides custom sorting order. |
Contract between equals, Comparable and Comparator
We know that, if Comparable returns 0 it means two objects are the same by comparison. Also By equals, we check if two objects are the same if it returns true. So the contract is: if two objects are equal by equality check then those objects must return 0 by Comparable or Comparator.
That’s it for now. Hope you have enjoyed this tutorial. If you have any doubt, please ask in the comment section. I will try to answer that as soon as possible. Till then, bye bye.