Why compareTo() and compare() exist?
In Java, objects don’t know how to compare themselves by default.
For example: If you create a List<Employee>
with id
, name
, and salary
, Java doesn’t know whether to sort them by id, or name, or salary.
So Java provides two mechanisms:
-
Comparable (
compareTo
) → defines a natural order inside the class. -
Comparator (
compare
) → allows creating custom orders outside the class.
They are mainly used for:
-
Sorting (
Collections.sort
,stream().sorted()
) -
Maintaining ordered collections (
TreeSet
,TreeMap
) -
Searching algorithms (
binarySearch
) -
Ensuring uniqueness based on comparison
Definition
-
Declared in:
java.lang.Comparable<T>
-
Used to define the natural ordering of objects.
-
A class implements Comparable when its objects can be compared naturally.
-
Only one natural order is allowed per class.
Method of Comparable interface
int compareTo(T other)
Definition:
-
Compares the current object (
this
) with the given object (other
). -
Defines the natural order of the class.
-
Implemented inside the class.
-
Return values:
-
0
→ this object is equal to other -
<0
→ this object comes before other in sorting order -
>0
→ this object comes after other in sorting order
-
-
Example use cases: sorting students by roll number, employees by ID, products by price.
-
Limitation: Only one implementation per class → best used when there’s a single obvious natural order.
Analogy: Think of roll numbers in a school – every student has a unique, natural order (1,2,3…). This is like
compareTo
. You can’t have multiple “natural” roll number orders for the same student list.
Notes / Output: Sorted ascending by id, streams use same compareTo, reverseOrder uses natural order reversed.
Example 2 — Comparable multiple parameters (sort by id, then name)
Notes: If id ties, name breaks tie. Good for deterministic natural order.
Example 3 — Comparable used by TreeSet (uniqueness decided by compareTo)
Notes: DuplicateBob not added because compareTo returned 0 vs existing id 1 — TreeSet treats it as duplicate.
Definition
-
Declared in:
java.util.Comparator<T>
-
Used to define custom orderings external to the class.
-
Multiple comparators can be defined for the same class.
Abstract Methods
-
compare(T o1, T o2)
-
Compares two objects (
o1
ando2
) to determine their relative order. -
Implemented outside the class (via lambda, anonymous class, or separate class).
-
Return values:
-
<0
→ o1 comes before o2 -
0
→ o1 is equal to o2 -
>0
→ o1 comes after o2
-
-
Use cases:
-
Sorting employees by salary, then by name.
-
Sorting products by price descending.
-
Sorting students by marks → age → name.
-
-
Unlike Comparable, multiple Comparators can exist for different orders.
Analogy: Different teachers grading the same class — one may sort students by marks, another by age, another by height.
-
-
equals(Object obj)
-
Inherited from Object.
-
Rarely overridden.
-
Default Methods (Java 8+)
-
reversed()
– Returns a comparator that reverses the current comparator. -
thenComparing(Comparator other)
– Chains comparators for tie-breaking. -
thenComparing(Function keyExtractor)
– Chains another field-based comparison. -
thenComparing(Function, Comparator)
– Chains comparison by extracted key with custom comparator. -
thenComparingInt/Long/Double(ToXFunction)
– Primitive-specific versions for efficiency.
Static Methods (Java 8+)
-
comparing(Function keyExtractor)
– Creates comparator based on key extraction. -
comparing(Function, Comparator)
– Same as above but with custom comparator. -
comparingInt/Long/Double(ToXFunction)
– Comparators for primitive fields. -
naturalOrder()
– Comparator using natural order (Comparable). -
reverseOrder()
– Comparator using reverse natural order. -
nullsFirst(Comparator cmp)
– Treats null as smaller than non-nulls. -
nullsLast(Comparator cmp)
– Treats null as larger than non-nulls.
Comparator Examples
Example 4 — compare(T o1, T o2)
via Anonymous Class & Lambda (sort by name ascending)
Example 5 — Comparator.comparing(...)
and comparingInt/Long/Double
Example 6 — reversed()
and reverseOrder()
Example 7 — thenComparing(Comparator)
and thenComparing(keyExtractor)
Example 8 — thenComparing(keyExtractor, keyComparator)
Example 9 — thenComparingInt/Long/Double
(primitive chaining)
Example 10 — comparing(keyExtractor, keyComparator)
Example 11 — nullsFirst()
and nullsLast()
Example 12 — naturalOrder()
and reverseOrder()
Example 13 — Overriding equals(Object)
for Comparator
Example 14 — TreeSet with Comparator (by name)
Example 15 — TreeMap with Comparator (descending keys)
Aspect | Comparable (compareTo) | Comparator (compare) |
Package | java.lang | java.util |
Method | int compareTo(T other) | int compare(T o1, T o2) |
Location of logic | Implemented inside the class | Defined outside the class (anonymous, lambda, separate class) |
Order types | Only one natural order per class | Multiple custom orders possible |
Modifies source code? | Yes (must modify class) | No (can sort without touching class code) |
Default order | Defines the natural/default order of objects | Provides alternative/custom orders |
Chaining | Not supported | Supported (thenComparing, reversed) |
TreeSet / TreeMap | Uses natural order | Uses comparator passed in constructor |
Static methods | None | Many helpers (comparing, comparingInt, reverseOrder, nullsFirst …) |
Flexibility | Less flexible | Highly flexible |
Best use case | When class has a single obvious natural order (e.g., Student roll number, Employee ID) | When you need multiple different sorting strategies (e.g., Employee by name, by salary, by ID) |
-
Use
Comparable
(compareTo
) when:-
The class has one natural order.
-
Example: Students sorted by roll number.
-
Implemented inside the class itself.
-
-
Use
Comparator
(compare
) when:-
You want multiple sorting strategies.
-
Example: Employees sorted by name, salary, or id differently.
-
Defined outside the class (lambda, anonymous, or separate comparator class).
-
-
Streams & Java 8+ → Comparator is more powerful (
comparing
,thenComparing
,reversed
, etc.) -
TreeSet / TreeMap rely on whichever comparison mechanism you give them:
-
If class implements Comparable → uses
compareTo
. -
If you pass Comparator → uses
compare
.
-
⚡ So the golden rule is:
π Comparable → default natural order (one per class)
π Comparator → custom / multiple orders (flexible)
id
) and multiple Comparators for custom orders (name
, salary
).
Output (Conceptual)
Key Learning from Case Study
-
Comparable → used for default / natural order (ID).
-
Comparator → used for multiple flexible orders (Name, Salary, Salary+Name).
-
Both can co-exist in the same class.
-
Streams API can also use the same comparators:
Comparable
(natural order) and Comparator
(custom order) for employee sorting.
Output (Conceptual)
Key Learnings
-
TreeSet
-
Uses
compareTo
if class implementsComparable
. -
Uses the given
Comparator
if provided. -
Considers elements duplicates if comparison result = 0.
-
-
TreeMap
-
Orders keys by their
compareTo
(if Comparable). -
Can use a custom
Comparator
for flexible ordering (e.g., salary, name). -
Keys with comparison result = 0 overwrite each other.
-
Comparable
and Comparator
co-exist and control ordering + uniqueness in Java collections.