Comparable and Comparators

Java provides two interfaces for sorting objects:

  • Comparable<T>: For natural ordering, implemented inside the class.
  • Comparator<T>: For custom ordering, implemented as external class or lambda.

Comparable Interface

public class Person implements Comparable<Person> {
    int age;
    String name;

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

    @Override
    public int compareTo(Person p) {
        if (this.age < p.age) return -1;   // Current object is "smaller"
        else if (this.age > p.age) return 1; // Current object is "larger"
        return 0; // Equal
    }
}

It is used in Tree based structures like TreeSet, TreeMap etc only if no external Comparator is provided.

Comparator Interface

Used when you want custom sorting logic - especially useful when:

  • You can’t modify the original class (e.g. library classes)
  • You want multiple different sorting criteria
public class Person {
    int age;
    String name;

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

class AgeComparator implements Comparator<Person> {
    public int compare(Person p1, Person p2) {
        return p1.age - p2.age;
    }
}

// Usage with PriorityQueue
PriorityQueue<Person> pq = new PriorityQueue<>(new AgeComparator());
pq.offer(new Person("Arjit", 10));
pq.offer(new Person("DidWhat", 20));

Note - Since Comparator is a functional interface (has only one abstract method), we can use a lambda instead of creating a full class.

  1. Comparator using Anonymous class ( not recommended )

    PriorityQueue<Person> pq = new PriorityQueue<>(new Comparator<Person>() {
        @Override
        public int compare(Person p1, Person p2) {
            return p1.age - p2.age;
        }
    });
    
  2. Comparator using Lambda Expression

    PriorityQueue<Person> pq = new PriorityQueue<>((p1, p2) -> p1.age - p2.age);