Comparator interface vs Comparable interface

Comparator interface vs Comparable interface

https://github.com/explorer436/programming-playground/tree/main/java-playground/my-java-solutions/src/main/java/com/my/company/sorting/objects

Streams-api has many nice features that support sort by using Comparators on the fly.

In Java language, the Comparator interface makes use of default methods heavily. See https://docs.oracle.com/javase/8/docs/api/java/util/Comparator.html

Let’s break down Comparable and Comparator. Both are Java interfaces used to define how objects of a particular class are ordered (sorted). The key difference lies in where the comparison logic resides and how flexible it is.

Comparable<T>

  1. Purpose: Defines the natural ordering for objects of a class. This is the single, most obvious way objects of this class should be sorted by default.
  2. Interface: java.lang.Comparable<T>
  3. Method: Requires implementing a single method: public int compareTo(T other)
  4. Implementation: The class whose instances need to be sorted must implement this interface itself.
  5. Logic: The compareTo method compares this object with the other object passed as an argument.
    • Returns a negative integer if this object comes before other.
    • Returns zero if this object is equal to other in terms of ordering.
    • Returns a positive integer if this object comes after other.
  6. Use Case: Used by sorting methods like Collections.sort(list) and Arrays.sort(array) when no explicit Comparator is provided. Also used by sorted data structures like TreeSet and TreeMap by default.
  7. Flexibility: Limited. Only allows one sorting implementation directly within the class.
  8. Example Classes: String, Integer, Double, Date all implement Comparable for their natural alphabetical/numerical/chronological order.

Comparator<T>

  1. Purpose: Defines custom or multiple alternative orderings for objects of a class. It decouples the comparison logic from the class being compared.
  2. Interface: java.util.Comparator<T>
  3. Method: Requires implementing a single method: public int compare(T o1, T o2) (Note: takes two objects).
  4. Implementation: A separate class implements this interface. This separate class defines how to compare two objects of type T. Often implemented using separate classes, anonymous inner classes, or lambda expressions (Java 8+).
  5. Logic: The compare method compares the two objects o1 and o2.
    • Returns a negative integer if o1 comes before o2.
    • Returns zero if o1 is equal to o2 in terms of this specific ordering.
    • Returns a positive integer if o1 comes after o2.
  6. Use Case: Used when:
    • You need to sort objects based on different criteria (e.g., sort Person objects by name, then by age, then by ID).
    • You want to sort objects of a class you cannot modify (e.g., from a third-party library).
    • You want to provide a specific order to methods like Collections.sort(list, comparator) or Arrays.sort(array, comparator).
    • You want to create sorted data structures like TreeSet or TreeMap with a custom order (new TreeSet<>(myComparator)).
  7. Flexibility: High. Allows multiple, independent sorting strategies for a single class without modifying the class itself.

Analogy

  1. Comparable: Think of people having an inherent, natural way to compare themselves, like by height. The height comparison logic is part of the Person class itself (compareTo).
  2. Comparator: Think of bringing in external judges. One judge compares people by weight (WeightComparator), another by running speed (SpeedComparator). These judges (Comparator implementations) are separate from the Person class and provide different ways to order people.

Comparison Table

Feature Comparable<T> Comparator<T>
Purpose Natural, default ordering Custom, multiple, external orderings
Interface java.lang.Comparable<T> java.util.Comparator<T>
Key Method int compareTo(T other) int compare(T o1, T o2)
Implementation Implemented by the class itself Implemented by a separate class
# Sort Logics One per class Many per class
Modification Requires modifying the class Does not require modifying the class
Default Sorting Used by default (sort(list)) Used when explicitly passed (sort(list, c))
Package java.lang java.util

When to Use Which

  1. Use Comparable when there’s a clear, single, natural way to order objects of your class. Implement it directly in your class.
  2. Use Comparator when:
    1. You need multiple ways to sort objects.
    2. You need to sort objects of a class you cannot modify.
    3. You want to keep sorting logic separate from the domain object’s core responsibilities.

The Comparator interface is more flexible and provides more control over the sorting behavior of objects. If you need to sort objects based on different criteria or if the objects do not implement the Comparable interface, you should use the Comparator interface. On the other hand, if you want to define the natural ordering of an object, you should use the Comparable interface.