Encodera

Thanks for reading!

Donate to the site — we work hard for you.

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:

true

Where 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
1

Use Integer.compare() — it always returns the right sign.

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.