Java Comparable and Comparator

Comparable and Comparator tell Java how to sort objects. Use Comparable for a class’s natural order, and use Comparator when you want a separate or alternate order.

Strings and numbers already know how to compare themselves. Your own classes, such as Student or Product, need comparison rules before Java can sort them in a meaningful way.

Comparable: Natural Order

A class implements Comparable<T> when it has one main sorting order. The class must define the compareTo() method.

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

public class Main {
    static class Student implements Comparable<Student> {
        String name;
        int grade;

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

        public int compareTo(Student other) {
            return Integer.compare(this.grade, other.grade);
        }

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

    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("Mia", 92));
        students.add(new Student("Ava", 85));
        students.add(new Student("Noah", 90));

        Collections.sort(students);

        System.out.println(students);
    }
}

Output:

[Ava(85), Noah(90), Mia(92)]

The compareTo() method returns a negative number when the current object should come before the other object, zero when they are equal for sorting, and a positive number when it should come after. Here, Integer.compare(this.grade, other.grade) sorts students from lowest grade to highest grade.

Comparator: Custom Order

A Comparator<T> is a separate object or lambda expression that compares two values. It is useful when you cannot edit the class, or when you need more than one sorting order.

import java.util.ArrayList;
import java.util.Comparator;

public class Main {
    static class Student {
        String name;
        int grade;

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

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

    public static void main(String[] args) {
        ArrayList<Student> students = new ArrayList<>();
        students.add(new Student("Mia", 92));
        students.add(new Student("Ava", 85));
        students.add(new Student("Noah", 90));

        students.sort(Comparator.comparing(student -> student.name));
        System.out.println("By name: " + students);

        students.sort(Comparator.comparingInt((Student student) -> student.grade).reversed());
        System.out.println("By grade: " + students);
    }
}

Output:

By name: [Ava(85), Mia(92), Noah(90)]
By grade: [Mia(92), Noah(90), Ava(85)]

The first sort uses Comparator.comparing() to sort by name. The second sort uses Comparator.comparingInt() and reversed() to sort by grade from highest to lowest.

Comparable Versus Comparator

Feature Comparable Comparator
Where rule lives Inside the class being sorted Outside the class being sorted
Main method compareTo(other) compare(a, b) or helper methods
Best use One natural order Many possible orders
Common examples Student by ID, task by due date Sort by name, then price, then rating

Sorting Collections

For lists, you can use Collections.sort(list) when the elements implement Comparable. You can also use list.sort(comparator) or Collections.sort(list, comparator) when you have a comparator.

Sorted collections such as TreeSet and TreeMap also need comparison rules. Their elements or keys must either have a natural order or be given a comparator when the collection is created.

Common Mistakes

  • Returning only 1 or -1 and never returning 0 for equal values.
  • Subtracting numbers inside comparisons, such as a - b, when Integer.compare(a, b) is safer and clearer.
  • Expecting Collections.sort() to work on custom objects without Comparable or a Comparator.
  • Forgetting that changing the comparator changes the meaning of sorted order in collections such as TreeSet.

Takeaway: use Comparable for a class’s normal sort order, and use Comparator whenever you need a custom sorting rule.