Comparable Vs Comparator Java — Interview
Sorting is a common task in programming, especially when dealing with lists of data. In Java, there are two interfaces that help us define sorting rules: Comparable
and Comparator
. Both are essential tools, but they serve different purposes and have distinct implementations. Let’s dive deeper to understand their differences, use cases with examples in detail.
What are Comparable
and Comparator
?
Comparable
: This interface allows a class to define its natural ordering. Think of it as the default way an object knows how to sort itself.Comparator
: This interface allows us to create custom sorting rules outside of the class. It’s like giving objects different instructions on how to be sorted.
Key Differences
🧑💻Using Comparable
Suppose we have a list of students, and we want to sort them by their ID numbers. With Comparable
, the sorting logic is built into the class itself.
import java.util.*;
class Student implements Comparable<Student> {
int id;
String name;
Student(int id, String name) {
this.id = id;
this.name = name;
}
// Defines the default sorting rule (by ID)
@Override
public int compareTo(Student other) {
return this.id - other.id; // Ascending order of IDs
}
@Override
public String toString() {
return id + " - " + name;
}
}
public class ComparableDemo {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(3, "Alice"),
new Student(1, "Bob"),
new Student(2, "Charlie")
);
Collections.sort(students); // Uses compareTo() to sort
System.out.println("Sorted by ID: " + students);
}
}
Output:
Sorted by ID: [1 - Bob, 2 - Charlie, 3 - Alice]
Here, the sorting logic is tied to the Student
class, making it the default way to sort students.
🧑💻 Using Comparator
Now, let’s say we want to sort the same students by their names instead of IDs. Using Comparator
, we can create a custom rule for sorting.
import java.util.*;
class Student {
int id;
String name;
Student(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return id + " - " + name;
}
}
public class ComparatorDemo {
public static void main(String[] args) {
List<Student> students = Arrays.asList(
new Student(3, "Alice"),
new Student(1, "Bob"),
new Student(2, "Charlie")
);
//used lambda expression
// Sort by name
students.sort((s1, s2) -> s1.name.compareTo(s2.name));
System.out.println("Sorted by Name: " + students);
// Sort by ID in descending order
students.sort((s1, s2) -> s2.id - s1.id);
System.out.println("Sorted by ID (Descending): " + students);
}
}
Output:
Sorted by Name: [3 - Alice, 1 - Bob, 2 - Charlie]
Sorted by ID (Descending): [3 - Alice, 2 - Charlie, 1 - Bob]
Here, we wrote sorting logic outside the Student
class, making it easy to define multiple sorting behaviors.
When to Use What?
Use Comparable
when:
- There is a single, natural way to sort your objects kind of default sorting.
- You want the sorting logic to be part of the class itself.
Use Comparator
when:
- You need different sorting rules for the same class.
- You don’t want to modify the class to define sorting logic.
- You’re dealing with classes from libraries where you can’t edit the source code kinda shared jar classes.
🚀 Pro Tip: Combining Both
You can use both Comparable
and Comparator
together. Define a default sorting rule with Comparable
, and use Comparator
for any additional sorting needs. This approach gives you the best of both worlds.