Java Comparable vs Comparator
Comparable and Comparator are interfaces in Java used for sorting objects. Comparable defines the natural ordering of a class by implementing compareTo() within the class itself. Comparator provides external sorting logic through the compare() method, allowing multiple sorting strategies without modifying the original class.
1. What is Comparable in Java?
Section titled β1. What is Comparable in Java?βComparable is an interface in Java that allows a class to define its natural ordering. When a class implements Comparable, it specifies how its objects should be compared and sorted by default.
public class Student implements Comparable<Student> { private String name; private int marks; @Override public int compareTo(Student other) { return this.marks - other.marks; // Natural ordering by marks }}2. Which method does Comparable use and what does it return?
Section titled β2. Which method does Comparable use and what does it return?βComparable uses the compareTo(T obj) method.
Returns:
- Negative integer (< 0): Current object is less than the specified object
- Zero (0): Current object is equal to the specified object
- Positive integer (> 0): Current object is greater than the specified object
@Overridepublic int compareTo(Student other) { return this.marks - other.marks; // Returns negative if this.marks < other.marks // Returns 0 if this.marks == other.marks // Returns positive if this.marks > other.marks}3. What is Comparator in Java?
Section titled β3. What is Comparator in Java?βComparator is an interface that provides external comparison logic for sorting objects. Itβs a separate class that defines how to compare two objects without modifying the original class.
class SortByName implements Comparator<Student> { @Override public int compare(Student s1, Student s2) { return s1.getName().compareTo(s2.getName()); }}4. Which method does Comparator use and what does it return?
Section titled β4. Which method does Comparator use and what does it return?βComparator uses the compare(T obj1, T obj2) method.
Returns:
- Negative integer: First object should come before second object
- Zero: Both objects are equal in ordering
- Positive integer: Second object should come before first object
@Overridepublic int compare(Student s1, Student s2) { return s1.getMarks() - s2.getMarks();}5. What is the key difference between Comparable and Comparator?
Section titled β5. What is the key difference between Comparable and Comparator?β| Aspect | Comparable (compareTo) | Comparator (compare) |
|---|---|---|
| Location | Implemented inside the class | External class/lambda |
| Method | compareTo(T obj) | compare(T obj1, T obj2) |
| Sorting Logic | Single natural ordering | Multiple custom orderings |
| Modification | Requires modifying the class | No modification needed |
| Usage | Collections.sort(list) | Collections.sort(list, comparator) |
6. When would you prefer Comparable?
Section titled β6. When would you prefer Comparable?βUse Comparable when:
- You want to define the default/natural ordering for your class
- Thereβs one obvious way to sort objects (e.g., students by ID, products by price)
- You have access to modify the class source code
- You want sorting to work automatically without passing extra parameters
// Once implemented, simple to useCollections.sort(students); // Uses natural ordering7. When would you prefer Comparator?
Section titled β7. When would you prefer Comparator?βUse Comparator when:
- You need multiple sorting strategies (sort by name, age, salary, etc.)
- You cannot modify the original class (third-party libraries, legacy code)
- You want flexibility to change sorting logic at runtime
- Different parts of your application need different sorting orders
// Multiple sorting strategiesCollections.sort(students, new SortByName());Collections.sort(students, new SortByMarks());Collections.sort(students, new SortByAge());8. Can a class have both Comparable and Comparator sorting?
Section titled β8. Can a class have both Comparable and Comparator sorting?βYes! A class can implement Comparable for natural ordering AND have multiple Comparators for alternative sorting.
// Class with Comparable (natural ordering by ID)class Employee implements Comparable<Employee> { private int id; private String name; private double salary; @Override public int compareTo(Employee other) { return this.id - other.id; // Natural ordering }}// Additional Comparators for different sortingComparator<Employee> byName = Comparator.comparing(Employee::getName);Comparator<Employee> bySalary = Comparator.comparing(Employee::getSalary);// UsageCollections.sort(employees); // Uses Comparable (by ID)Collections.sort(employees, byName); // Uses Comparator (by name)Collections.sort(employees, bySalary); // Uses Comparator (by salary)9. How do you sort a list using Comparator with Java 8?
Section titled β9. How do you sort a list using Comparator with Java 8?βJava 8 provides multiple elegant ways:
Method 1: Lambda expression
employees.sort((e1, e2) -> e1.getName().compareTo(e2.getName()));Method 2: Comparator.comparing() with method reference
employees.sort(Comparator.comparing(Employee::getName));Method 3: Stream API
List<Employee> sorted = employees.stream() .sorted(Comparator.comparing(Employee::getSalary)) .collect(Collectors.toList());Method 4: List.sort() method
employees.sort(Comparator.comparing(Employee::getName));10. How do you sort using Comparable with Collections.sort()?
Section titled β10. How do you sort using Comparable with Collections.sort()?βSimply pass the list to Collections.sort() without any comparator:
List<Student> students = new ArrayList<>();students.add(new Student("Alice", 85));students.add(new Student("Bob", 92));students.add(new Student("Charlie", 78));// Sorts using compareTo() method defined in Student classCollections.sort(students);// Java 8 alternativestudents.sort(null); // Uses natural ordering (Comparable)Requirement: The class must implement Comparable<T> interface.
11. Which one supports multiple sorting strategies?
Section titled β11. Which one supports multiple sorting strategies?βComparator supports multiple sorting strategies. You can create as many Comparators as needed for different sorting criteria without modifying the original class.
// Multiple strategies with ComparatorComparator<Employee> byName = Comparator.comparing(Employee::getName);Comparator<Employee> bySalary = Comparator.comparing(Employee::getSalary);Comparator<Employee> byAge = Comparator.comparing(Employee::getAge);// Comparable only provides ONE natural ordering12. Can Comparator sort by multiple fields? Which method is used? (thenComparing())
Section titled β12. Can Comparator sort by multiple fields? Which method is used? (thenComparing())βYes! Comparator can sort by multiple fields using thenComparing() method for chaining:
// Sort by department, then by salary, then by nameComparator<Employee> multiFieldComparator = Comparator .comparing(Employee::getDepartment) .thenComparing(Employee::getSalary) .thenComparing(Employee::getName);employees.sort(multiFieldComparator);Advanced examples:
// Reverse order for salaryComparator<Employee> comparator = Comparator .comparing(Employee::getDepartment) .thenComparing(Employee::getSalary, Comparator.reverseOrder()) .thenComparing(Employee::getName);// Custom comparison for second fieldComparator<Employee> custom = Comparator .comparing(Employee::getDepartment) .thenComparingDouble(Employee::getSalary) .thenComparingInt(Employee::getAge);13. Where are Comparable and Comparator located (which package)?
Section titled β13. Where are Comparable and Comparator located (which package)?β- Comparable:
java.lang.Comparable- part ofjava.langpackage (no import needed) - Comparator:
java.util.Comparator- part ofjava.utilpackage (requires import)
// Comparable - no import needed (java.lang package)public class Student implements Comparable<Student> { }// Comparator - requires importimport java.util.Comparator;public class NameComparator implements Comparator<Student> { }14. Which one defines natural ordering?
Section titled β14. Which one defines natural ordering?βComparable defines the natural ordering. Natural ordering is the default way objects of a class should be sorted.
// Comparable defines natural orderingclass Student implements Comparable<Student> { @Override public int compareTo(Student other) { return this.id - other.id; // Natural ordering by ID }}// Comparator provides alternative/custom orderingComparator<Student> byName = Comparator.comparing(Student::getName);Examples of natural ordering:
- Integer: ascending numeric order (1, 2, 3β¦)
- String: alphabetical order (A, B, Cβ¦)
- Date: chronological order (oldest to newest)
15. How do you handle sorting when the field may be null? (nullsFirst / nullsLast)
Section titled β15. How do you handle sorting when the field may be null? (nullsFirst / nullsLast)βUse Comparator.nullsFirst() or Comparator.nullsLast() to handle null values safely:
nullsFirst() - Null values appear first:
Comparator<Employee> comparator = Comparator.nullsFirst(Comparator.comparing(Employee::getName));employees.sort(comparator); // Result: null employees first, then sorted by namenullsLast() - Null values appear last:
Comparator<Employee> comparator = Comparator.nullsLast(Comparator.comparing(Employee::getName));employees.sort(comparator); // Result: sorted employees first, null employees lastHandling null fields (not null objects):
// If name field itself can be nullComparator<Employee> comparator = Comparator.comparing(Employee::getName, Comparator.nullsFirst(String::compareTo));// Or more conciselyComparator<Employee> comparator = Comparator.comparing(Employee::getName, Comparator.nullsFirst(Comparator.naturalOrder()));employees.sort(comparator);Complete example with multiple fields and null handling:
Comparator<Employee> safeComparator = Comparator .comparing(Employee::getDepartment, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(Employee::getSalary, Comparator.nullsFirst(Comparator.reverseOrder())) .thenComparing(Employee::getName, Comparator.nullsLast(String::compareTo));employees.sort(safeComparator);Why this matters:
Without null handling, sorting with null values throws NullPointerException. Using nullsFirst() or nullsLast() makes your code robust and handles edge cases gracefully.