Найти разницу полей в двух объектах, полученных при помощи методов min/max в Stream API
Есть список каких-то людей. Нужно этот список передать в метод, найти в нем самого молодого и самого старого, затем найти разницу между их зарплатами.
Собственно в "передать в другой метод" никаких проблем нет. Через стрим найти самого молодого и самого старого тоже могу.
Есть класс Employees с приватными полями и соответствующими геттерами и список List<Employees>:
public class Employees {
private String name;
private String secondName;
private int salary;
private int age;
// геттеры, сеттеры, конструктор
}
Самого молодого и самого старого нахожу так:
Object oldestEmployee = list.stream().max(Comparator.comparing(Employees::getAge));
Object youngestEmployee = list.stream().min(Comparator.comparing(Employees::getAge));
Как найти разницу в зарплате, если новые объекты не принимают поля старых объектов?
Возможно ли это сделать через стрим, чтобы не прописывать огромный кусок кода?
Ответы (1 шт):
Терминальные операции Stream::min и Stream::max возвращают тип Optional<T>.
Этот тип представляет собой обёртку для обработки возможных null значений (у пустого потока минимальное и максимальное значения будут отсутствовать, и тогда будет возвращаться "пустой" объект Optional.empty). Разумеется, у типа Optional нет геттеров соответствующего класса.
Поэтому для поиска зарплаты самого старого и самого молодого сотрудника можно использовать методы Optional::map (для вызова геттера зарплаты) и Optional::orElse для обработки пустого значения.
public static int calcSalaryDifference(List<Employees> employees) {
int oldestSalary = employees.stream()
.max(Comparator.comparingInt(Employees::getAge)) // Optional<Employees>
.map(Employees::getSalary) // Optional<Integer>
.orElse(0);
int youngestSalary = employees.stream()
.min(Comparator.comparingInt(Employees::getAge)) // Optional<Employees>
.map(Employees::getSalary) // Optional<Integer>
.orElse(0);
return youngestSalary - oldestSalary;
}
Найти зарплаты самого старшего и самого младшего сотрудника можно и за один проход при помощи метода Stream::reduce, также возвращающего Optional<T> значения, и класса/кортежа (record) для хранения пары "младший - старший".
record YoungOld(Employees youngest, Employees oldest) {
YoungOld(Employees e) {
this(e, e);
}
}
public static int calcSalaryDifferenceOneRun(List<Employees> employees) {
return employees.stream()
.map(YoungOld::new) // Stream<YoungOld>
.reduce((a, b) -> new YoungOld(
a.getAge() < b.getAge() ? a : b, // младший из двух
a.getAge() > b.getAge() ? a : b // старший из двух
)) // Optional<YoungOld>
.map(yo -> yo.youngest().getSalary() - yo.oldest().getSalary())
.orElse(0);
}