← Back to Home

Comparable vs Comparator

Comparable and Comparator are used in Java to define sorting logic for objects. They answer two different questions:

  • Comparable: How should this object be compared to another of the same type?
  • Comparator: How should two objects be compared using an external rule?

This is a very high-frequency interview topic.

What Is Comparable?

Comparable is an interface that defines natural ordering of objects.

public interface Comparable<T> {
    int compareTo(T o);
}
          

Key Points

  • Implemented inside the class
  • Defines default / natural order
  • Affects TreeSet, TreeMap, Collections.sort()
  • Only one sorting logic per class

Comparable Example

class Student implements Comparable<Student> {
    int id;
    String name;

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

    @Override
    public int compareTo(Student s) {
        return this.id - s.id; // sort by id
    }
}

List<Student> list = new ArrayList<>();
Collections.sort(list);
          

✔ Sorting happens automatically

✔ Uses compareTo()

What Is Comparator?

Comparator is a separate object that defines custom sorting logic.

public interface Comparator<T> {
    int compare(T o1, T o2);
}
          

Key Points

  • Implemented outside the class
  • Allows multiple sorting strategies
  • Used when class cannot be modified
  • Preferred for flexibility

Comparator Example

class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return s1.name.compareTo(s2.name);
    }
}

Collections.sort(list, new NameComparator());
          

✔ Sorts by name

✔ Class remains unchanged

Comparator Using Lambda (Java 8+)

Collections.sort(list, (s1, s2) -> s1.name.compareTo(s2.name));
          

✔ Clean

✔ Concise

✔ Modern approach

Sorting with TreeSet / TreeMap

Using Comparable

TreeSet<Student> set = new TreeSet<>();
          

✔ Uses compareTo()

Using Comparator

TreeSet<Student> set =
    new TreeSet<>((a, b) -> a.name.compareTo(b.name));
          

✔ Uses custom logic

Comparable vs Comparator (Interview Favorite Table)

Aspect Comparable Comparator
Package java.lang java.util
Method compareTo() compare()
Sorting logic Inside class Outside class
Number of strategies One Multiple
Class modification Required Not required
Flexibility Less More

Return Values of compare / compareTo (Important)

Return Value Meaning
0 Objects equal
< 0 First object smaller
> 0 First object greater

Real-World Analogy

Comparable

Student knows how to compare itself with another student (by roll number)

Comparator

External examiner compares students by name, marks, or age

Common Beginner Mistakes

  • Confusing equals() with compareTo()
  • Returning wrong comparison values
  • Not handling null values
  • Using subtraction for large numbers (overflow risk)
  • Forgetting consistency with equals()

Best Practices

  • Use Comparable for natural/default order
  • Use Comparator for alternate sorting
  • Prefer Comparator.comparing() (Java 8+)
  • Ensure comparison logic is consistent with equals()
  • Avoid subtraction for comparison (use Integer.compare())
return Integer.compare(this.id, s.id);
          

Interview-Ready Answers

Short Answer

Comparable is used for natural ordering, while Comparator is used for custom ordering.

Detailed Answer

In Java, Comparable defines a class’s natural ordering using the compareTo() method, whereas Comparator defines external sorting logic using the compare() method. Comparable allows only one sorting order, while Comparator supports multiple sorting strategies and greater flexibility.

Key Takeaway

Comparable = natural order (inside class). Comparator = custom order (outside class). Use Comparable for default sorting and Comparator for flexible, multiple sorting rules.

Extended Examples

1. Comparable – Natural Ordering (Single Logic)

class Student implements Comparable<Student> {
    int id;

    Student(int id) {
        this.id = id;
    }

    public int compareTo(Student s) {
        return this.id - s.id;
    }

    public String toString() {
        return "" + id;
    }
}

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<Student> list = Arrays.asList(
                new Student(3),
                new Student(1),
                new Student(2)
        );
        Collections.sort(list);
        System.out.println(list);
    }
}
          

Output

[1, 2, 3]
          

2. Comparable Affects Default Sorting

import java.util.*;

class Demo {
    public static void main(String[] args) {
        TreeSet<Student> set = new TreeSet<>();
        set.add(new Student(2));
        set.add(new Student(1));
        System.out.println(set);
    }
}
          

Explanation

  • TreeSet uses compareTo()
  • Mandatory for natural ordering

3. Comparator – External Sorting Logic

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(3, 1, 2);

        Collections.sort(list, (a, b) -> b - a); // descending
        System.out.println(list);
    }
}
          

Output

[3, 2, 1]
          

4. Sorting Custom Object Using Comparator

class Employee {
    int salary;
    Employee(int salary) {
        this.salary = salary;
    }

    public String toString() {
        return "" + salary;
    }
}

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<Employee> list = Arrays.asList(
                new Employee(5000),
                new Employee(3000)
        );

        Collections.sort(list, (a, b) -> a.salary - b.salary);
        System.out.println(list);
    }
}
          

Output

[3000, 5000]
          

5. Multiple Sorting Logic Using Comparator

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<Employee> list = Arrays.asList(
                new Employee(5000),
                new Employee(3000)
        );

        Collections.sort(list, (a, b) -> b.salary - a.salary);
        System.out.println(list);
    }
}
          

Explanation

  • Multiple sort strategies possible
  • Not possible with Comparable alone

6. Comparator with TreeSet

import java.util.*;

class Demo {
    public static void main(String[] args) {
        TreeSet<Integer> set =
                new TreeSet<>((a, b) -> b - a);
        set.add(1);
        set.add(3);
        set.add(2);
        System.out.println(set);
    }
}
          

Output

[3, 2, 1]
          

7. Comparable vs Comparator – Method Location

// Comparable → inside class
public int compareTo(T o)

// Comparator → separate class / lambda
public int compare(T o1, T o2)
          

8. Comparator Using Separate Class

import java.util.*;

class SalaryComparator implements Comparator<Employee> {
    public int compare(Employee a, Employee b) {
        return a.salary - b.salary;
    }
}

class Demo {
    public static void main(String[] args) {
        List<Employee> list = Arrays.asList(
                new Employee(4000),
                new Employee(2000)
        );
        Collections.sort(list, new SalaryComparator());
        System.out.println(list);
    }
}
          

9. Comparable Limitation – Only One Sorting Rule

class User implements Comparable<User> {
    int age;

    User(int age) {
        this.age = age;
    }

    public int compareTo(User u) {
        return this.age - u.age;
    }
}
          

Explanation

Cannot sort by name without Comparator.

10. Comparator with Method Reference

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("Java", "API", "Test");
        list.sort(Comparator.comparingInt(String::length));
        System.out.println(list);
    }
}
          

Output

[API, Test, Java]
          

11. Comparator.thenComparing()

class Person {
    int age;
    String name;

    Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public String toString() {
        return age + "-" + name;
    }
}

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<Person> list = Arrays.asList(
                new Person(30, "B"),
                new Person(30, "A"),
                new Person(20, "C")
        );

        list.sort(Comparator
                .comparingInt((Person p) -> p.age)
                .thenComparing(p -> p.name));

        System.out.println(list);
    }
}
          

Output

[20-C, 30-A, 30-B]
          

12. compareTo() Returning 0 Means Duplicate (TreeSet Trap)

class User implements Comparable<User> {
    int id;
    User(int id) { this.id = id; }

    public int compareTo(User u) {
        return this.id - u.id;
    }
}

import java.util.*;

class Demo {
    public static void main(String[] args) {
        TreeSet<User> set = new TreeSet<>();
        set.add(new User(1));
        set.add(new User(1));
        System.out.println(set.size());
    }
}
          

Output

1
          

13. Comparator Allows Sorting Without Modifying Class

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("B", "A");
        Collections.sort(list, Comparator.naturalOrder());
        System.out.println(list);
    }
}
          

14. Sorting Map Keys Using Comparator

import java.util.*;

class Demo {
    public static void main(String[] args) {
        TreeMap<Integer, String> map =
                new TreeMap<>(Comparator.reverseOrder());
        map.put(1, "A");
        map.put(2, "B");
        System.out.println(map);
    }
}
          

Output

{2=B, 1=A}
          

15. Comparable vs Comparator – Compilation Rule

// TreeSet without Comparator requires Comparable
TreeSet<Student> set = new TreeSet<>();

// Otherwise

ClassCastException
          

16. Comparator Using Anonymous Class (Old Style)

Collections.sort(list, new Comparator<Employee>() {
    public int compare(Employee a, Employee b) {
        return a.salary - b.salary;
    }
});
          

17. Null Handling with Comparator

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List<String> list = Arrays.asList("A", null, "B");
        list.sort(Comparator.nullsLast(String::compareTo));
        System.out.println(list);
    }
}
          

Output

[A, B, null]
          

18. Performance Concept

  • Comparable → faster (built-in)
  • Comparator → flexible (external)

19. Real Interview Comparison

  • Comparable → natural ordering
  • Comparator → custom ordering

20. Interview Summary – Comparable vs Comparator

Comparable<T>   // compareTo()
Comparator<T>   // compare()
          

Key Points

  • Comparable → inside class, one logic
  • Comparator → outside class, multiple logics
  • TreeSet / TreeMap rely on comparison
  • Returning 0 means duplicate
  • Comparator is more flexible