Codectionary / Developer documentation / Java

Comparable & Comparator

Comparable and Comparator both define how to order objects, but serve different purposes. A class implements Comparable<T> to define its single 'natural' ordering via compareTo(), used automatically by Collections.sort() and TreeSet. A Comparator is a separate object passed alongside a collection to define one or more custom, alternative orderings, without modifying the class being sorted at all.

Syntax

class X implements Comparable<X> { public int compareTo(X other) { } }

Examples

Implementing Comparable

Defining a class's single natural ordering.

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

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

    @Override
    public int compareTo(Student other) {
        return this.grade - other.grade;  // ascending order by grade
    }

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

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

ArrayList<Student> students = new ArrayList<>();
students.add(new Student("John", 85));
students.add(new Student("Zain", 92));
students.add(new Student("Jamal", 78));

Collections.sort(students);  // uses compareTo() automatically
System.out.println(students);  // [Jamal(78), John(85), Zain(92)]

Using a Comparator for Custom Order

A Comparator lets you sort the same objects in a different way without changing the class.

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

ArrayList<Student> students = new ArrayList<>();
students.add(new Student("John", 85));
students.add(new Student("Zain", 92));
students.add(new Student("Jamal", 78));

students.sort(Comparator.comparing(s -> s.name));  // sort by name instead
System.out.println(students);  // [Jamal(78), John(85), Zain(92)]

students.sort(Comparator.comparingInt((Student s) -> s.grade).reversed());
System.out.println(students);  // [Zain(92), John(85), Jamal(78)]

Chaining Comparators

Sorting by multiple criteria: primary key first, then a secondary key for ties.

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

class Employee {
    String department;
    String name;
    Employee(String department, String name) {
        this.department = department;
        this.name = name;
    }
    public String toString() { return department + ": " + name; }
}

ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("Engineering", "Zain"));
employees.add(new Employee("Sales", "John"));
employees.add(new Employee("Engineering", "Amir"));

employees.sort(
    Comparator.comparing((Employee e) -> e.department)
              .thenComparing(e -> e.name)
);

System.out.println(employees);
// [Engineering: Amir, Engineering: Zain, Sales: John]

Best practices

  • Implement Comparable when a class has one obvious, natural ordering (like numbers by value, or dates chronologically)
  • Use a Comparator when you need multiple different orderings, or when you cannot modify the class being sorted (like a class from a library)
  • Use Comparator.comparing() with method references or lambdas for concise, readable comparator definitions instead of writing compare() by hand
  • Chain comparators with .thenComparing() for multi-level sorting (sort by one field, then break ties with another)

Runtime & versions

Java Virtual Machine. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

Java Language Specification

Specifications & further reading