How to rewrite the valuemapper function using java lambda
Is it possible / correct (to) or rewrite the following with lambda? Here, I provide an inline implementation for the keymapper and valuemapper functions
public Map<Integer,List<Employee>> getSubordinateHighestSalEmpMapV1(List<Employee> employees) { return employees.stream() .filter(e -> e.getSubordinates() != null) .collect(Collectors.toMap( //keyMapper new Function<Employee,Integer>() { @Override public Integer apply(Employee t) { return t.getId(); } },new Function<Employee,List<Employee>>() {//valueMapper @Override public List<Employee> apply(Employee t) { List<Employee> subordinates = t.getSubordinates(); List<Employee> subOrdinatesListWithHighestSalary = new ArrayList<>(); int maxSal = Integer.MIN_VALUE; for(Employee s: subordinates) { if(s.getSalary() >= maxSal) { maxSal = s.getSalary(); } } for(Employee s: subordinates) { if(s.getSalary() == maxSal) { subOrdinatesListWithHighestSalary.add(s); } } return subOrdinatesListWithHighestSalary; } })); }
What do I want to achieve:
Employee class has list < employee > subordinates I want to get the highest salary among the subordinates of every employee Every employee may or may not have subordinates If the subordinate is not present, it is not included in the result If more than one subordinate has the same highest salary, all subordinates should appear in the results
For example, it is similar to getting the highest paid employee in each department (employee, if salary matches)
Employee. java
import java.util.List; public class Employee{ private int id; private int salary; private List<Employee> subordinates; private String name; private int age; public int getId() { return id; } public Employee setId(int id) { this.id = id; return this; } public int getSalary() { return salary; } public Employee setSalary(int salary) { this.salary = salary; return this; } public List<Employee> getSubordinates() { return subordinates; } public Employee setSubordinates(List<Employee> subordinates) { this.subordinates = subordinates; return this; } public String getName() { return name; } public Employee setName(String name) { this.name = name; return this; } public int getAge() { return age; } public Employee setAge(int age) { this.age = age; return this; } @Override public String toString() { return "Employee [id=" + id + ",salary=" + salary + ",name=" + name + ",age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if (id != other.id) return false; return true; } }
For example, for the following inputs:
>Employee1 (ID: 100) has employee2, employee3, employee4, etc. employee3 pays up to 30000, which should be part of the output > employee2 (ID: 101) has employee5 and employee6, in which the maximum salary of employee5 is 20000, which should be part of the output > employee3 (ID: 102) has employee7 and employee8, both of which have 16000 salaries, and the output should include both. > Employee8 (ID: 107) has a subordinate employee9 with a salary of 12000. Employee9 should be part of the output
Enter as follows:
private static List<Employee> getEmployeeListV1() { int i = 100; Employee employee1 = (Employee) new Employee().setId(i++).setSalary(10000).setAge(101).setName("emp 1"); Employee employee2 = (Employee) new Employee().setId(i++).setSalary(20000).setAge(110).setName("emp 2"); Employee employee3 = (Employee) new Employee().setId(i++).setSalary(30000).setAge(20).setName("emp 3"); Employee employee4 = (Employee) new Employee().setId(i++).setSalary(10000).setAge(32).setName("emp 4"); Employee employee5 = (Employee) new Employee().setId(i++).setSalary(20000).setAge(34).setName("emp 5"); Employee employee6 = (Employee) new Employee().setId(i++).setSalary(15000).setAge(44).setName("emp 6"); Employee employee7 = (Employee) new Employee().setId(i++).setSalary(16000).setAge(56).setName("emp 7"); Employee employee8 = (Employee) new Employee().setId(i++).setSalary(16000).setAge(65).setName("emp 8"); Employee employee9 = (Employee) new Employee().setId(i++).setSalary(12000).setAge(74).setName("emp 9"); employee1.setSubordinates(Stream.of(employee2,employee4).collect(Collectors.toList())); employee2.setSubordinates(Stream.of(employee5,employee6).collect(Collectors.toList())); employee3.setSubordinates(Stream.of(employee7,employee8).collect(Collectors.toList())); employee8.setSubordinates(Stream.of(employee9).collect(Collectors.toList())); List<Employee> employees = Stream.of(employee1,employee2,employee4,employee5,employee7,employee8,employee9).collect(Collectors.toList()); return employees; }
The following is the output:
100=[Employee [id=102,salary=30000,name=emp 3,age=20]] 101=[Employee [id=104,salary=20000,name=emp 5,age=34]] 102=[Employee [id=106,salary=16000,name=emp 7,age=56],Employee [id=107,name=emp 8,age=65]] 107=[Employee [id=108,salary=12000,name=emp 9,age=74]]
Interpretation:
Solution
Of course, you can change keymapper to lambda using method references (Employee:: getid or lambda employee – > employee. Getid()) and valuemapper (t – > {...), as follows:
return employees.stream() .filter(e -> e.getSubordinates() != null) .collect(Collectors.toMap( //keyMapper Employee::getId,t -> { List<Employee> subordinates = t.getSubordinates(); List<Employee> subOrdinatesListWithHighestSalary = new ArrayList<>(); int maxSal = Integer.MIN_VALUE; for(Employee s: subordinates) { if(s.getSalary() >= maxSal) { maxSal = s.getSalary(); } } for(Employee s: subordinates) { if(s.getSalary() == maxSal) { subOrdinatesListWithHighestSalary.add(s); } } return subOrdinatesListWithHighestSalary; }));
You can further simplify the method:
return employees.stream() .filter(e -> e.getSubordinates() != null) .collect(Collectors.toMap(Employee::getId,t -> { int maxSal = t.getSubordinates().stream().mapToInt(Employee::getSalary).max().orElse(Integer.MIN_VALUE); return t.getSubordinates().stream().filter(x -> x.getSalary() == maxSal).collect(toCollection(ArrayList::new)); }));
Even further:
return employees.stream() .filter(e -> e.getSubordinates() != null) .collect(Collectors.toMap(Employee::getId,Main::apply));
Since you have this method:
static List<Employee> apply(Employee t) { List<Employee> subordinates = t.getSubordinates(); int maxSal = subordinates.stream().mapToInt(Employee::getSalary).max().orElse(Integer.MIN_VALUE); return subordinates.stream().filter(x -> x.getSalary() == maxSal).collect(toCollection(ArrayList::new)); }
Main refers to the class containing the apply helper method