Найти разницу полей в двух объектах, полученных при помощи методов 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 шт):

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

Терминальные операции 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);
}
→ Ссылка