Search code examples
javajava-8collectors

Retrieving employee department and id based on the salary using Java streams


I have a list of Employees

[employeeId=22, employeeName= Rajan Anand, department= Engineering, salary=1600000]

[employeeId=23, employeeName= Swati Patil, department= Testing, salary=800000]

[employeeId=27, employeeName= Vijay Chawda, department= Engineering, salary=800000]

[employeeId=29, employeeName= Basant Mahapatra, department= Engineering, salary=600000]

[employeeId=32, employeeName= Ajay Patel, department= Testing, salary=350000]

[employeeId=34, employeeName= Swaraj Birla, department= Testing, salary=350000]

I want to collect department and id of the employee with maximum salary in that department in a Map<String,Integer>.

Sample Output:

Engineering 22

Testing 23

The attempted code

Map<String, Optional<Employee>> retVal = new HashMap<String, Optional<Employee>>();
retVal = employeeList.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.maxBy(Comparator.comparing(Employee::getSalary))));

This implementation I have added and I am getting department as a key and the highest salary Employee as a value but I want only employee id as the value.


Solution

  • #1 - current approach

    Provided what you've attempted, you can extend the same pipeline to stream again over the entries and map the values as following:

    Map<String, Optional<Integer>> retVal = employeeList.stream()
            .collect(Collectors.groupingBy(Employee::getDepartment,
                    Collectors.maxBy(Comparator.comparing(Employee::getSalary))))
            .entrySet().stream()
            .collect(Collectors.toMap(Map.Entry::getKey,
                    e -> e.getValue().map(Employee::getId)));
    

    #2 - single stream approach

    Now if you were to look for abstracting the streaming over entries and perform the operation with a single collect operation, then you can make use of Hadi's solution.

    #3 - lookup approach

    As a suggestion(though with two times iteration), if I was to extend this and make it flexible for further use, I would first prepare a lookup map for the id to the salary of the employees

    Map<Integer, Integer> employeeSalary = employeeList.stream()
            .collect(Collectors.toMap(Employee::getId, Employee::getSalary));
    

    using this map to further attain the mapping as you currently desire is also convenient though, such as :

    Map<String, Integer> retVal = employeeList.stream()
            .collect(Collectors.toMap(Employee::getDepartment, Employee::getId,
                    BinaryOperator.maxBy(Comparator.comparing(employeeSalary::get))));