Sorting with Comparable and Comparator
Sorting with Comparable and Comparator
Sorting is everywhere in application code, and Java makes it both simple and dangerous: if you sort without thinking about contracts, you can end up with inconsistent ordering and subtle bugs. The two key interfaces are Comparable and Comparator, and knowing when to use each is half the battle.
Comparable
Comparable defines the natural ordering of a class. A class implements it using a single method, compareTo, which returns a negative integer, zero, or a positive integer when this object is less than, equal to, or greater than the argument. Natural order should stay consistent with equals to avoid confusing behavior in sorted collections.
public class Player implements Comparable<Player> {
private final String name;
private final int score;
public Player(String name, int score) {
this.name = name;
this.score = score;
}
@Override
public int compareTo(Player other) {
return Integer.compare(this.score, other.score);
}
}
Comparator
When you want to sort the same class multiple ways, use a Comparator. Since Java 8 you build comparators fluently, and you can chain them with thenComparing. A comparator takes two elements and returns the same negative, zero, or positive verdict as compareTo, but it lives outside the class.
players.sort(Comparator.comparingInt(Player::getScore)
.reversed()
.thenComparing(Player::getName));
System.out.println(players);
Notice the sort method: List.sort modifies the list in place, while Stream.sorted returns a new stream. The Comparator interface offers helpers such as comparing, comparingInt, naturalOrder, and nullsLast that make intent obvious and reduce boilerplate.
Sorting rules
Always make compareTo or your comparator total and consistent: if a.compareTo(b) is zero, then a.equals(b) should be true. Arrays and collections sort with a stable, adaptive merge sort (TimSort), so equal elements keep their original relative order.
Key Points
Comparabledefines an object's natural order viacompareTo.Comparatordefines external sort orders and composes fluently.- Prefer
Comparator.comparingIntandthenComparingover verbose anonymous classes. - Keep ordering consistent with
equalsto avoid subtle bugs. List.sortmutates in place;Stream.sortedproduces a new stream.