Как сделать объекты сравнимыми
Короткий ответ
Реализуйте 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() — Сортирует список на месте.