Как работает метод sort() для списка вместе с Comparator в Java 18

У меня есть класс родитель Animal и его производные Dog, Cat, Hamster, Pig.

Dog и Cat реализуют функционал интерфейса Omnivore (всеядный), а Pig и Hamster реализуют Herbivore (травоядный). Моя задача по принадлежности к интерфейсу отсортировать животных. Придумал вот такой метод сортировки:

public static void sortList(List<Animal> pets) {

        pets.sort(Comparator.comparing(pet -> pet instanceof Animal.Omnivore ? 1 : 0));

}

Но не до конца понимаю, как это работает. У меня есть догадка, что в параметре pet каким-то образом хранится экземпляр объекта из pets, но я не уверен, что это так. Поэтому хочу спросить: откуда он берется?) Если это так, то как он перебирает список и запихивает экземпляр в pet?


Ответы (1 шт):

Автор решения: Nowhere Man

У меня есть догадка, что в параметре pet каким-то образом хранится экземпляр объекта из pets, но я не уверен, что это так.

Догадка в целом верная, в параметр pet и будет "подставляться" каждый элемент из списка pets в процессе сортировки.
Подобная реализация сортировки работает c 2014 лет со времени выпуска Java 8 (а не Java 18) :).

Можно расписать всё по порядку:

pets.sort(Comparator.comparing(pet -> pet instanceof Animal.Omnivore ? 1 : 0));
  1. У экземпляра списка c животными pets вызывается метод List::sort(Comparator<? super E> c) (где E - супер-тип для элементов списка, т.е. Animal в данном случае),
  2. который принимает на вход экземпляр компаратора, созданный при помощи статического фабричного метода Comparator.comparing(Function<? super E, ? extends Comparable> keyExtractor),
  3. который принимает на вход некоторую функцию, преобразующую экземпляры типа E (элементы нашего списка) в "сравнимые" экземпляры, т.е. реализующие интерфейс Comparable.

В данном случае эта функция описана в виде лямбды
pet -> pet instanceof Animal.Omnivore ? 1 : 0,
которая принимает на вход экземпляры типа Animal и приводит их к типу Integer.

Но можно было бы ещё упростить код, убрав тернарный оператор и параметр pet, заменив указанную лямбда-функцию с оператором instanceof ссылкой на метод Class::isInstance соответствующего интерфейса.

pets.sort(Comparator.comparing(Animal.Omnivore.class::isInstance));

Этот метод будет так же вызываться для каждого элемента списка и обеспечит аналогичную сортировку, так как он возвращает результат типа boolean, который так же является Comparable:
false < true.

P.S. Свиньи -- всеядны (см. википедию и фильм Snatch), в отличие от морских свинок GuineaPig

→ Ссылка