Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как сделать объекты сравнимыми

Короткий ответ

Реализуйте Comparable и метод compareTo(). Он возвращает отрицательное число, если этот объект меньше, ноль — если равен, положительное — если больше:

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);
}

Результат:

[Version[major=1, minor=9], Version[major=2, minor=0], Version[major=2, minor=1]]

Через Comparator

Метод compareTo() удобно реализовать через готовый компаратор:

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);
}

Результат:

true

Где это работает

Естественный порядок используют sort(), TreeSet, TreeMap, Collections.max() и потоки:

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));
}

Результат:

Version[major=1, minor=5]
Version[major=3, minor=0]

Частая ошибка

Сравнивать через вычитание: return a - b. Для больших чисел разность переполняется, и знак меняется:

void main() {
    int a = 2_000_000_000;
    int b = -2_000_000_000;
 
    IO.println(a - b);
    IO.println(Integer.compare(a, b));
}

Результат:

-294967296
1

Используйте Integer.compare() — он всегда возвращает правильный знак.

Функции из этого ответа

  • Comparable.compareTo() — Задаёт естественный порядок объектов класса — по нему работают sort() и TreeSet.
  • Comparator.comparing() — Создаёт компаратор, который сравнивает объекты по одному полю.
  • Collections.sort() — Сортирует список на месте.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.