0Pricing
Java Academy · Lesson

The Comparable Interface

Implement Comparable to give a class a natural ordering and use it with Collections.sort.

The Comparable Interface is a free Java Academy lesson on CoddyKit — lesson 1 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

The Comparable Interface

Comparable<T> gives a class a natural ordering. Implement it to make instances sortable with Collections.sort(), Arrays.sort(), and sorted collections like TreeSet.

Implementing Comparable

Implement compareTo(T other) returning negative (this < other), zero (equal), or positive (this > other).

class Product implements Comparable<Product> {
    private final String name;
    private final double price;

    Product(String name, double price) {
        this.name = name; this.price = price;
    }

    @Override
    public int compareTo(Product other) {
        return Double.compare(this.price, other.price); // ascending by price
    }

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

List<Product> products = new ArrayList<>(List.of(
    new Product("Mouse", 29.99),
    new Product("Laptop", 999.0),
    new Product("Keyboard", 79.99)
));
Collections.sort(products);
System.out.println(products); // [Mouse($29.99), Keyboard($79.99), Laptop($999.0)]

The compareTo Contract

Implementing Comparable correctly requires satisfying a contract:

  • Antisymmetry: sgn(a.compareTo(b)) == -sgn(b.compareTo(a))
  • Transitivity: if a > b and b > c, then a > c
  • Consistency: a.compareTo(b) == 0 implies a.equals(b) is strongly recommended

Comparing Primitives Safely

Never subtract primitives in compareTo — integer overflow can give wrong results. Use Integer.compare(), Double.compare(), etc.

// WRONG: integer subtraction can overflow
int compareTo(Player other) {
    return this.score - other.score; // overflow if scores differ by > Integer.MAX_VALUE
}

// CORRECT: use Integer.compare
int compareTo(Player other) {
    return Integer.compare(this.score, other.score);
}

// For strings: delegate to String.compareTo
int compareTo(Player other) {
    return this.name.compareTo(other.name); // String handles it correctly
}

Natural Ordering in TreeSet

Classes implementing Comparable get automatic placement in sorted collections like TreeSet and TreeMap.

class Priority implements Comparable<Priority> {
    enum Level { LOW, MEDIUM, HIGH, CRITICAL }
    final Level level;
    final String task;
    Priority(Level level, String task) { this.level = level; this.task = task; }
    @Override
    public int compareTo(Priority other) {
        return this.level.compareTo(other.level); // enum ordinal order
    }
    @Override public String toString() { return level + ": " + task; }
}

TreeSet<Priority> queue = new TreeSet<>();
queue.add(new Priority(Priority.Level.CRITICAL, "Fix prod crash"));
queue.add(new Priority(Priority.Level.LOW, "Update docs"));
queue.add(new Priority(Priority.Level.HIGH, "Deploy feature"));
queue.forEach(System.out::println);
// LOW: Update docs
// HIGH: Deploy feature
// CRITICAL: Fix prod crash

Multi-Field Comparable

To sort by multiple fields, chain comparisons: primary, then secondary if primary is equal.

class Employee implements Comparable<Employee> {
    final String dept, name;
    final double salary;

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

    @Override
    public int compareTo(Employee other) {
        int deptCmp = this.dept.compareTo(other.dept);
        if (deptCmp != 0) return deptCmp;           // primary: by dept
        return this.name.compareTo(other.name);      // secondary: by name
    }
}

Comparable and equals Consistency

It is strongly recommended (but not required) that a.compareTo(b) == 0 iff a.equals(b). Violating this causes subtle bugs in sorted sets and maps.

// BigDecimal violates this: new BigDecimal("2.0").compareTo(new BigDecimal("2.00")) == 0
// but new BigDecimal("2.0").equals(new BigDecimal("2.00")) == false

// This causes TreeSet to treat them as equal (only one stored)
TreeSet<java.math.BigDecimal> set = new TreeSet<>();
set.add(new java.math.BigDecimal("2.0"));
set.add(new java.math.BigDecimal("2.00"));
System.out.println(set.size()); // 1 — compareTo-equal → same element

Sorting with Collections.sort

Collections.sort() and Arrays.sort() use the natural order defined by Comparable.

List<String> names = new ArrayList<>(List.of("Charlie", "Alice", "Bob"));
Collections.sort(names); // natural alphabetical order
System.out.println(names); // [Alice, Bob, Charlie]

String[] arr = {"banana", "apple", "cherry"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr)); // [apple, banana, cherry]

// Stream sorted() uses natural order
names.stream().sorted().forEach(System.out::println);

Comparable in Binary Search

Collections.binarySearch() requires the list to be sorted by natural order and the elements to implement Comparable.

List<Integer> sorted = new ArrayList<>(List.of(1, 3, 5, 7, 9, 11));
int idx = Collections.binarySearch(sorted, 7);
System.out.println("Found 7 at index: " + idx); // 3

int missing = Collections.binarySearch(sorted, 4);
System.out.println("4 not found, insertion point: " + (-missing - 1)); // 2

Comparable vs Comparator

Key distinction:

  • Comparable: defines the class's own natural ordering — one per class
  • Comparator: defines an external ordering — unlimited, composable

Practical: Leaderboard

A leaderboard using Comparable for natural score-descending order.

class LeaderboardEntry implements Comparable<LeaderboardEntry> {
    final String player;
    final int score;
    final long timestamp;

    LeaderboardEntry(String player, int score) {
        this.player = player; this.score = score;
        this.timestamp = System.nanoTime();
    }

    @Override
    public int compareTo(LeaderboardEntry other) {
        int scoreCmp = Integer.compare(other.score, this.score); // descending
        if (scoreCmp != 0) return scoreCmp;
        return Long.compare(this.timestamp, other.timestamp); // earlier = higher
    }

    @Override public String toString() { return player + ": " + score; }
}

TreeSet<LeaderboardEntry> board = new TreeSet<>();
board.add(new LeaderboardEntry("Alice", 950));
board.add(new LeaderboardEntry("Bob", 1200));
board.add(new LeaderboardEntry("Carol", 950));
board.forEach(System.out::println);
// Bob: 1200 / Alice: 950 / Carol: 950

Quick Check

What does compareTo() return when the current object is less than the argument?

Recap: The Comparable Interface

Key takeaways:

  • Implement Comparable to define a class's natural ordering
  • compareTo returns negative (less), zero (equal), positive (greater)
  • Use Integer.compare()/Double.compare() — never subtract (overflow risk)
  • Chain comparisons for multi-field sorting: primary → secondary
  • Natural order is used by Collections.sort, Arrays.sort, TreeSet, TreeMap
  • Comparable defines ONE ordering; use Comparator for multiple orderings

Frequently asked questions

Is the “The Comparable Interface” lesson free?

Yes — the full text of “The Comparable Interface” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.

What will I learn in “The Comparable Interface”?

Implement Comparable to give a class a natural ordering and use it with Collections.sort. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Java Academy?

No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “The Comparable Interface” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Java Academy lesson?

Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. The Comparable Interface
  2. Comparator and Lambda Sorting
  3. Multi-Key Sorting with thenComparing
  4. Sorting Arrays and Collections in Practice
← Back to Java Academy