使用 IntSummaryStatistics 跨多个字段求平均值

Squ*_*gs. 2 java java-8 java-stream

我正在尝试使用 Java 8 流来创建一个 CarData 对象,该对象由列表中所有 CarData 字段的平均值组成getCars

   CarData = new CarData();
   CarData.getBodyWeight returns Integer
   CarData.getShellWeight returns Integer
Run Code Online (Sandbox Code Playgroud)
     List<CarData> carData = carResults.getCars();
    
    IntSummaryStatistics averageBodyWeight = carData.stream()
            .mapToInt((x) -> x.getBodyWeight())
            .summaryStatistics();
    
    averageBodyWeight.getAverage(); 


            IntSummaryStatistics averageShellWeight = carData.stream()
            .mapToInt((x) -> x.getShellWeight())
            .summaryStatistics();
    
    getShellWeight.getAverage(); 
Run Code Online (Sandbox Code Playgroud)

我不想在我最终返回的结果中把这些都放在一起。

视觉上,这是我的清单

getCars() : [
 {CarData: { getBodyWeight=10, getShellWeight=3 } }
 {CarData: { getBodyWeight=6, getShellWeight=5 } }
 {CarData: { getBodyWeight=8, getShellWeight=19 } }
]
Run Code Online (Sandbox Code Playgroud)

我试图实现的输出是一个对象,它具有我指定的每个字段的平均值。不确定我是否需要使用Collectors.averagingInt或 IntSummaryStatistics 的一些组合来实现这一点。对于这些技术中的任何一种,在一个字段中都可以轻松完成,只是不确定在使用多个整数字段时我缺少什么。

 {CarData: { getBodyWeight=8, getShellWeight=9 } }
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 5

从 JDK 12 开始,您可以使用以下解决方案:

CarData average = carData.stream().collect(Collectors.teeing(
    Collectors.averagingInt(CarData::getBodyWeight),
    Collectors.averagingInt(CarData::getShellWeight),
    (avgBody, avgShell) -> new CarData(avgBody.intValue(), avgShell.intValue())));
Run Code Online (Sandbox Code Playgroud)

对于较旧的 Java 版本,您可以执行以下任一操作:将这个答案teeing实现添加到您的代码库中并完全按照上述方式使用它,或者创建一个为您的任务量身定制的自定义收集器,如Andreas 的答案所示。

或者考虑List在内存中流式传输两次不一定比在一个流中执行两个操作更糟糕,无论是可读性还是性能。

请注意,调用intValue()Double对象具有相同的行为(int)在Andreas的答案转换。因此,无论哪种情况,如果需要其他舍入行为,您都必须调整代码。

或者您考虑使用不同的结果对象,能够为平均值保存两个浮点值。