Java Stream - maxBy - 如何使用 Java 8 查找平均工资最高的部门

nik*_*kar 1 java java-stream collectors

我有一份清单Employee

public class Employee {
    private String department;
    private double salary;
    // other properties
}
Run Code Online (Sandbox Code Playgroud)

我正在尝试查找平均工资最高的部门的名称。

我尝试过的代码:

List<Employee> employeeList = new ArrayList<Employee>();
employeeList.add(new Employee("abc", 38, "M", "QA", 115000.00d, 2016));
employeeList.add(new Employee("def", 23, "M", "Sports", 5000000.00d, 2011));
employeeList.add(new Employee("ghi", 38, "M", "QA", 120000.00d, 2007));
employeeList.add(new Employee("jkl", 35, "M", "DEV", 50000.00d, 2016));
employeeList.add(new Employee("mno", 30, "F", "QA", 80000.00d, 206));
employeeList.add(new Employee("pqr", 32, "F", "DEV", 75000.00d, 2014));

Map<String, Double> highestAvgSalary = employeeList.stream()
    .collect(Collectors.groupingBy(
        emp -> emp.getDepartment(),
        Collectors.averagingDouble(emp -> emp.getSalary(),                        
            Collectors.maxBy(Comparator.comparingDouble(emp -> emp.getSalary()))
Run Code Online (Sandbox Code Playgroud)

代码的最后一行触发编译错误。我如何申请才能maxBy()获得该部门的最高平均工资?

Ale*_*nko 5

Collectors.averagingDouble()只需要一个参数 - 一个将流元素转换为 的函数Double。尝试传递下游收集器是不正确的。

正如@Sayan Bhattacharya在评论中提到的,此任务无法通过对员工集合的单次迭代来完成。

我们需要在中间体的映射条目上创建一个流Map,将禁止名称与其平均工资相关联,并max()对其进行应用操作。

Map.Entry<String, Double> highestAvgSalary = employeeList.stream()
    .collect(Collectors.groupingBy(
        Employee::getDepartment,
        Collectors.averagingDouble(Employee::getSalary)
    ))
    .entrySet().stream()
    .max(Map.Entry.comparingByValue())
    .get();
Run Code Online (Sandbox Code Playgroud)

请注意max()会产生一个Optional. 可选 API 提供了从中提取结果的不同方法。如果选项为空,方法get()可能会生成NoSuchElementException如果您有针对这种情况的自定义例外 - 将其替换为orElseThrow(Supplier). 由于根据文档,get() 不鼓励使用 Java 10(除非您不确定结果是否存在),因此建议的做法是使用orElseThrow(). 显然,您不能将它与Java 8一起使用,只是出于这个原因,在我应用的上面的代码中get()(对于较低版本,避免冗长是有道理的)。但您还有其他选择,例如orElse()orElseGet()

另请注意,作为Map结果类型不会很方便,因为您事先不知道工资最高的部门的名称(这将是地图中包含的唯一条目的键)。因此,您无法以方便的方式访问此类地图中的信息。但是,如果您出于某种原因确实需要单条目映射,那么您可以应用而不是get()上面的代码,map(Map::ofEntries).get()它会给您Map<String, Double>结果。