В чем разница между Comparator и Comparable в Java?
Что проверяют
Знаете ли вы, где живёт порядок сортировки: внутри класса или снаружи. Заодно проверяют владение современным API компараторов.
Как отвечать
Comparable описывает естественный порядок самого объекта: класс реализует интерфейс и метод compareTo. Порядок один, он часть класса, и именно он используется в TreeSet, TreeMap и Collections.sort без дополнительных аргументов.
Comparator это внешнее правило сравнения, отдельный объект. Их может быть сколько угодно, они не требуют доступа к исходному коду класса и передаются в сортировку явно.
Практически: если порядок один и очевиден (числа, даты, идентификаторы), делают Comparable. Если порядков несколько или класс чужой, пишут Comparator.
orders.sort(Comparator
.comparing(Order::status)
.thenComparing(Order::createdAt, Comparator.reverseOrder())
.thenComparing(Order::id));Что стоит добавить:
- современный API:
comparing,thenComparing,reversed,nullsFirstиnullsLast, специализированныеcomparingIntиcomparingLongбез упаковки; - контракт: сравнение обязано быть согласованным и транзитивным, иначе
Arrays.sortброситIllegalArgumentExceptionпро нарушение контракта. Классическая ошибка это сравнение через вычитание чисел, которое переполняется; - согласованность с
equalsжелательна: еслиcompareToвозвращает ноль для объектов, которые не равны,TreeSetпосчитает их одним элементом и потеряет данные.
Где спотыкаются
Пишут return a.value - b.value и ловят переполнение на больших числах.
Кладут в TreeSet объекты с компаратором по одному полю и удивляются, что дубликаты пропали.
Не знают про thenComparing и городят ветвления внутри одного компаратора.