How to make objects comparable
Short answer
Implement Comparable and the compareTo() method. It returns a negative number if this object is smaller, zero if equal, and a positive number if larger:
record Version(int major, int minor) implements Comparable<Version> {
@Override
public int compareTo(Version other) {
if (major != other.major) {
return Integer.compare(major, other.major);
}
return Integer.compare(minor, other.minor);
}
}
void main() {
var versions = new ArrayList<>(List.of(new Version(2, 1), new Version(1, 9), new Version(2, 0)));
Collections.sort(versions);
IO.println(versions);
}Output:
[Version[major=1, minor=9], Version[major=2, minor=0], Version[major=2, minor=1]]With a Comparator
It is convenient to implement compareTo() with a ready-made comparator:
record Version(int major, int minor) implements Comparable<Version> {
private static final Comparator<Version> ORDER =
Comparator.comparingInt(Version::major).thenComparingInt(Version::minor);
@Override
public int compareTo(Version other) {
return ORDER.compare(this, other);
}
}
void main() {
IO.println(new Version(1, 10).compareTo(new Version(1, 2)) > 0);
}Output:
trueWhere it works
Natural ordering is used by sort(), TreeSet, TreeMap, Collections.max() and streams:
record Version(int major, int minor) implements Comparable<Version> {
@Override
public int compareTo(Version other) {
return major != other.major ? Integer.compare(major, other.major) : Integer.compare(minor, other.minor);
}
}
void main() {
var set = new TreeSet<>(List.of(new Version(3, 0), new Version(1, 5)));
IO.println(set.first());
IO.println(Collections.max(set));
}Output:
Version[major=1, minor=5]
Version[major=3, minor=0]Common mistake
Comparing by subtraction: return a - b. For large numbers the difference overflows and the sign flips:
void main() {
int a = 2_000_000_000;
int b = -2_000_000_000;
IO.println(a - b);
IO.println(Integer.compare(a, b));
}Output:
-294967296
1Use Integer.compare() — it always returns the right sign.
Functions used in this recipe
- Comparable.compareTo() — Defines the natural order of a class — used by sort() and TreeSet.
- Comparator.comparing() — Creates a comparator that compares objects by one key.
- Collections.sort() — Sorts a list in place.