DEV Community

realNameHidden
realNameHidden

Posted on

⚖️ What’s the Difference Between Comparable and Comparator in Java?

Learn the difference between Comparable and Comparator in Java with simple examples, use cases, and best practices to master custom object sorting.


🏁 Introduction

Imagine you’re sorting a list of your favorite movies — maybe by their release year, rating, or title. Depending on what you choose, the order changes! In Java, we often face similar situations when sorting objects like students, employees, or products.

That’s where Comparable and Comparator come into play. These two interfaces in Java help you define custom sorting logic for your objects — whether it’s sorting names alphabetically, marks in descending order, or prices from low to high.

In this article, we’ll clearly explain the difference between Comparable and Comparator, walk through practical examples, and share best practices to help you avoid common pitfalls.


💡 Core Concepts

🔹 Comparable — Natural Ordering

The Comparable interface defines a default or natural ordering for the objects of a class.
It belongs to the java.lang package and contains a single method:

int compareTo(T obj);
Enter fullscreen mode Exit fullscreen mode

When a class implements Comparable, it decides how its objects should be compared — like how strings are alphabetically ordered by default.

Key Points:

  • Used to define natural order of objects (e.g., alphabetical, ascending order).
  • Implemented inside the class being sorted.
  • Used by methods like Collections.sort() or Arrays.sort().
  • Allows only one sorting logic per class.

Example: Students sorted by their roll numbers.


🔹 Comparator — Custom or External Ordering

The Comparator interface, on the other hand, allows you to define multiple sorting strategies outside the class.
It belongs to the java.util package and defines the method:

int compare(T obj1, T obj2);
Enter fullscreen mode Exit fullscreen mode

You can use different comparators for different sorting needs — for example, one for sorting by name, another by marks.

Key Points:

  • Used to define custom or multiple orderings.
  • Implemented outside the class being sorted.
  • Often used with Collections.sort() or List.sort().
  • Can be implemented using lambda expressions (Java 8+).

Think of Comparable as a default sorting rule (like alphabetical order in a dictionary), and Comparator as custom sorting (like sorting by page length, or date added).


🔸 Quick Comparison Table

Feature Comparable Comparator
Package java.lang java.util
Method compareTo(Object o) compare(Object o1, Object o2)
Where Defined Inside the class Outside the class
Sorting Type Natural (default) Custom (multiple)
Multiple Sorts Possible? No Yes
Used With Collections.sort(list) Collections.sort(list, comparator)
Example Use Case Sort students by ID Sort students by name, marks, etc.

💻 Code Examples

✅ Example 1: Using Comparable (Natural Ordering)

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

class Student implements Comparable<Student> {
    private int rollNo;
    private String name;

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

    // Define natural ordering (by roll number)
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.rollNo, other.rollNo);
    }

    @Override
    public String toString() {
        return rollNo + " - " + name;
    }
}

public class ComparableExample {
    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(3, "Rahul"));
        students.add(new Student(1, "Amit"));
        students.add(new Student(2, "Sneha"));

        Collections.sort(students); // uses compareTo()

        System.out.println("Students sorted by roll number:");
        students.forEach(System.out::println);
    }
}
Enter fullscreen mode Exit fullscreen mode

🧩 Explanation:
Here, Student implements Comparable<Student> and overrides compareTo() to sort by roll number.
Collections.sort() automatically applies this natural ordering.


✅ Example 2: Using Comparator (Custom Ordering)

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

class Employee {
    private String name;
    private double salary;

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() { return name; }
    public double getSalary() { return salary; }

    @Override
    public String toString() {
        return name + " - $" + salary;
    }
}

public class ComparatorExample {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Riya", 60000));
        employees.add(new Employee("Arjun", 75000));
        employees.add(new Employee("Meena", 55000));

        // Comparator to sort by salary (descending)
        Comparator<Employee> bySalaryDesc = (e1, e2) -> Double.compare(e2.getSalary(), e1.getSalary());

        // Comparator to sort by name (alphabetically)
        Comparator<Employee> byName = Comparator.comparing(Employee::getName);

        // Sort using different comparators
        Collections.sort(employees, bySalaryDesc);
        System.out.println("Employees sorted by salary (descending):");
        employees.forEach(System.out::println);

        Collections.sort(employees, byName);
        System.out.println("\nEmployees sorted by name:");
        employees.forEach(System.out::println);
    }
}
Enter fullscreen mode Exit fullscreen mode

🧩 Explanation:
Here, we defined two different comparators:

  • One sorts employees by salary (descending).
  • Another sorts by name (alphabetically).

This flexibility is what makes Comparator powerful — you can plug in as many sorting rules as you need.


🧠 Best Practices

  1. Use Comparable for natural sorting.
    Define a single, logical ordering that represents the class’s identity — like sorting Student by rollNo.

  2. Use Comparator for flexibility.
    When multiple sorting rules are needed, prefer Comparator. You can even chain them using thenComparing().

  3. Avoid mixing both unnecessarily.
    If a class already has Comparable, use external comparators only for alternate orders.

  4. Leverage Java 8+ features.
    Use lambda expressions and method references for cleaner, more readable comparator code.

  5. Watch out for null values.
    Handle nulls explicitly using Comparator.nullsFirst() or Comparator.nullsLast() to avoid NullPointerException.


🏁 Conclusion

In Java programming, Comparable and Comparator both help define how objects are compared and sorted — but they serve different purposes:

  • Comparable defines the default sorting logic inside the class.
  • Comparator allows external, flexible sorting rules outside the class.

Mastering when and how to use them will make you more confident when working with complex sorting scenarios — from lists of names to detailed data models in enterprise applications.


Top comments (0)