Помогите, пожалуйста понять сортировку в Stram Api java

Есть пара нюансов, которые никак не могу понять.

Пример: У меня есть класс Person. Стандартный POJO класс, описывающий людей, с простыми и понятными полями, такими как имя, фамилия, возраст и т.п.

Задачи также стандартные, например отфильтровать всех, кто совершеннолетний, или только женщин.

Фильтрация работает, а вот с сортировкой - проблемы.

Я написал 3 варианта сортировки

Comparator<Person> byFamily = (Person o1, Person o2 )-> o1.getFamily().compareTo(o2.getFamily());
Comparator<Person> byFamily2 = Comparator.comparing(Person::getFamily);
Comparator<Person> byName = Comparator.comparing(Person::getName);

Не обращайте внимание на качество кода, учусь.

Далее задача, получить в List отсортированные по фамилии данные.

List<String> workers = persons.stream()
                .filter(person -> person.getAge()>=18)
                .filter(person -> person.getEducation() == Education.HIGHER)
                .map(Person::getFamily)
                .sorted(byFamily2);
                .collect(Collectors.toList());

Почему не работает sorted? Я же в предыдущем шаге в map получил String из фамилий ((


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

Автор решения: insolor

Метод .map() применяет переданную в него функцию ко всем объектам стрима, и формирует новый стрим из возвращенных значений. Если у вас был Stream<Person>, передана функция, принимающая Person и возвращающая String, значит дальше уже идет Stream<String>.

После .map(Person::getFamily) уже идет стрим состоящий строк (фамилий), и получается, что при сортировке вы из каждой фамилии внутри компаратора еще раз фамилию пытаетесь вытащить.

Используйте или .sorted() (просто сортируйте стрим фамилий как строки), или перенесите .sorted(byFamily2) выше .map(Person::getFamily).

Т.е. или так:

List<String> workers = persons.stream()
                .filter(person -> person.getAge()>=18)
                .filter(person -> person.getEducation() == Education.HIGHER)
                .map(Person::getFamily)  // Stream<Person> превращается в Stream<String>
                .sorted();  // Просто сортируем стрим строк
                .collect(Collectors.toList());

или так:

List<String> workers = persons.stream()
                .filter(person -> person.getAge()>=18)
                .filter(person -> person.getEducation() == Education.HIGHER)
                .sorted(byFamily2)  // Сортируем Stream<Person> с помощью компаратора byFamily2
                .map(Person::getFamily)  // Stream<Person> превращается в Stream<String>
                .collect(Collectors.toList());

Если нужно сортировать по одному полю, а потом извлекать другое поле (например, сортировать по имени, извлекать фамилию), то естественно сортировать нужно до извлечения второго поля, т.е. по второму варианту.

→ Ссылка