Помогите, пожалуйста понять сортировку в 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 шт):
Метод .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());
Если нужно сортировать по одному полю, а потом извлекать другое поле (например, сортировать по имени, извлекать фамилию), то естественно сортировать нужно до извлечения второго поля, т.е. по второму варианту.