Sorting stability and safe comparators
See why two sorts in a row still work, and why comparing with a - b is a real bug.
Open this lesson in the learning hubKey points
List.sortuses TimSort, which is stable: elements that compare equal keep their existing order.- That is why sorting by name and then by team leaves every team still ordered by name.
- One comparator with
thenComparingis clearer and faster than two separate sorting passes. - Never compare with
a - b. It overflows for large or negative values and silently reverses the order. - Use
Integer.compare,comparingIntorComparator.comparing— all of them are overflow safe. Arrays.sorton primitives is a quicksort and is not stable, but identical primitives are indistinguishable anyway.
Example
import java.util.*;
public class Main {
record Row(String name, String team) {
@Override public String toString() { return name + "/" + team; }
}
public static void main(String[] args) {
List<Row> rows = new ArrayList<>(List.of(
new Row("di", "ops"), new Row("cy", "eng"),
new Row("bo", "ops"), new Row("ana", "eng")));
rows.sort(Comparator.comparing(Row::name));
System.out.println("sorted by name : " + rows);
rows.sort(Comparator.comparing(Row::team));
System.out.println("then by team : " + rows);
System.out.println("inside each team the name order survived - that is stability");
rows.sort(Comparator.comparing(Row::team).thenComparing(Row::name));
System.out.println("one comparator : " + rows + " (clearer than two passes)");
int big = Integer.MAX_VALUE;
int small = -10;
System.out.println("big - small : " + (big - small) + " (overflowed, wrong sign)");
System.out.println("Integer.compare : " + Integer.compare(big, small) + " (always right)");
int[] prims = {3, 1, 2};
Arrays.sort(prims);
System.out.println("primitive sort : " + Arrays.toString(prims) + " (quicksort, stability meaningless)");
}
}
Stability is what lets you sort in layers; Integer.compare is what keeps each layer correct.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Collections course, and every lesson in it is listed on the Collections contents page.