Как отсортировать коллекцию объектов по одному или нескольким полям
Что проверяют
Знаете ли вы современный API Comparator и его подводные камни, а не только Collections.sort. После простого случая почти всегда просят отсортировать по одному полю по убыванию, а по другому по возрастанию.
Как отвечать
Два способа задать порядок:
Comparable: класс реализуетcompareToи получает естественный порядок. Годится, когда порядок один и очевиден, как у дат или сумм;Comparator: порядок задаётся снаружи класса, и вариантов может быть сколько угодно. Для сортировки по нескольким полям это основной путь.
Компаратор собирается цепочкой (для record геттеры выглядят как Person::lastName):
people.sort(Comparator.comparing(Person::lastName).thenComparing(Person::firstName).thenComparingInt(Person::age))
Что стоит проговорить:
comparingIntиthenComparingInt: для примитивов, без упаковки вInteger;- направление для одного поля:
thenComparing(Person::age, Comparator.reverseOrder()). Вызовreversed()в конце цепочки развернёт весь порядок, а не только последнее поле; null:Comparator.comparing(Person::lastName, Comparator.nullsLast(Comparator.naturalOrder())), иначе будетNullPointerException;- строки:
String.CASE_INSENSITIVE_ORDERдля сравнения без регистра,Collatorдля порядка с учётом языка; - где сортировать:
list.sort(...)меняет список на месте,stream().sorted(cmp).toList()возвращает новый. Сортировка объектов в Java стабильная (TimSort) и работает за O(n log n), элементы с равными ключами сохраняют исходный порядок.
Где спотыкаются
Пишут компаратор вычитанием: (a, b) -> a.age - b.age. На больших по модулю значениях вычитание переполняется, и порядок ломается. Правильно Integer.compare(a.age, b.age) или comparingInt.
Пишут Comparator.comparing(p -> p.getName()).reversed() и получают ошибку компиляции: в такой цепочке компилятор не выводит тип лямбды и считает p объектом Object. Помогает ссылка на метод или явный тип (Person p) -> ....
Сортируют список из List.of(...) или stream().toList(). Он неизменяемый, и sort бросит UnsupportedOperationException.