导读:本期聚焦于澳门程序员创作的《Java里的DoubleSummaryStatistics怎么用?一文搞懂数值流的数据统计》,敬请观看详情。Collectors.summarizingDouble 返回的 DoubleSummaryStatistics 到底能做什么?它是 JDK 8 引入的一个专门用于 double 数值统计的小工具类,一次 collect 操作就能同时拿到元素个数、总和、最小值、最大值和平均值,比手动遍历流去分别计算要省事得多。本文会讲清楚它的常用方法与实际用法,包括通过 Stream.mapToDouble 转成 DoubleStream 后调用 summaryStatistics 的方式,以及它在分组统计、与 averagingDouble 等收集器的对比、注意事项和典型应用场景,帮助你写出更简洁高效的统计代码。

在 Java 8 之前,如果要对一组 double 数值做统计,比如算出总和、平均值、最大值、最小值,通常要写一个循环,在里面累加求和、不断比较更新最大最小值,代码又长又容易出错。Java 8 的流 API 引入了一个专门解决这类问题的工具类——DoubleSummaryStatistics,它能让我们在一次遍历中同时收集所有统计数据,配合 collectors 使用非常简洁。这篇文章就来详细聊聊它的具体用法。

Java里的DoubleSummaryStatistics怎么用?一文搞懂数值流的数据统计

DoubleSummaryStatistics 是什么

DoubleSummaryStatistics 是 JDK 8 中 java.util 包下的一个类,从名字就能看出它的定位:double 数值的汇总统计。它内部维护了四个状态:计数 count、总和 sum、最小值 min、最大值 max,平均值则是通过 sum 除以 count 计算得来的。

这个类实现了 DoubleConsumer 接口,也就是说它本身就是一个消费者,可以直接调用它的 accept(double) 方法逐个接收数值并更新统计状态。同时它还提供了 combine(DoubleSummaryStatistics) 方法,用于把两个统计对象合并起来,这正是它能够支持并行流统计的关键——每个线程统计自己那部分数据,最后再合并结果。

它的常见获取方式有两种:一种是使用 Collectors.summarizingDouble() 收集器,另一种是先把流转成 DoubleStream 再调用 summaryStatistics() 方法。两种方式本质一样,选择哪种更多是写法习惯的问题。

基础用法示例

先看第一种方式,使用 Collectors.summarizingDouble。假设有一个订单列表,需要统计所有订单金额的各项指标:

import java.util.Arrays;
import java.util.List;
import java.util.DoubleSummaryStatistics;
import java.util.stream.Collectors;

public class Demo {
    public static void main(String[] args) {
        List<Order> orders = Arrays.asList(
                new Order("A001", 129.5),
                new Order("A002", 88.0),
                new Order("A003", 259.9),
                new Order("A004", 45.0)
        );

        DoubleSummaryStatistics stats = orders.stream()
                .collect(Collectors.summarizingDouble(Order::getAmount));

        System.out.println("订单数量: " + stats.getCount());
        System.out.println("总金额: " + stats.getSum());
        System.out.println("平均金额: " + stats.getAverage());
        System.out.println("最小金额: " + stats.getMin());
        System.out.println("最大金额: " + stats.getMax());
    }
}

第二种方式更直接,把流转成 DoubleStream 后调用 summaryStatistics()

DoubleSummaryStatistics stats = orders.stream()
        .mapToDouble(Order::getAmount)
        .summaryStatistics();

long count = stats.getCount();
double avg = stats.getAverage();

两种写法输出的结果完全一致。区别在于 mapToDouble 的方式少了一层收集器的包装,可读性更好一些;而 summarizingDouble 的方式在分组统计等复杂场景下更方便,后面会提到。

主要方法一览

DoubleSummaryStatistics 提供的方法不多,但都很实用,下面逐个说明:

  • accept(double value):接收一个数值并纳入统计,常用于非流场景的手动统计。
  • combine(DoubleSummaryStatistics other):合并另一个统计对象的状态,并行流内部会自动调用。
  • getCount():返回已统计的元素个数,类型为 long。
  • getSum():返回所有数值的总和,类型为 double。
  • getMin():返回最小值,如果没统计过任何数据则返回 Double.POSITIVE_INFINITY
  • getMax():返回最大值,没数据时返回 Double.NEGATIVE_INFINITY
  • getAverage():返回算术平均值,没数据时返回 Double.NaN

需要特别注意空数据时的返回值。很多人会以为空流统计出的最小值是 0,实际上没有元素参与统计时,min 是正无穷,max 是负无穷,average 是 NaN。如果不做判断就直接拿去展示或参与计算,很容易出问题:

DoubleSummaryStatistics empty = new DoubleSummaryStatistics();
System.out.println(empty.getMin());      // Infinity
System.out.println(empty.getMax());      // -Infinity
System.out.println(empty.getAverage());  // NaN
System.out.println(empty.getSum());      // 0.0

所以在实际使用时,建议先通过 getCount() 判断是否有数据,再做后续处理。

配合 groupingBy 做分组统计

DoubleSummaryStatistics 真正方便的地方在于和 Collectors.groupingBy 组合使用。比如要按部门统计工资情况,传统写法需要先分组再对每组分别遍历,而用 downstream 收集器一行就能搞定:

Map<String, DoubleSummaryStatistics> statsByDept = employees.stream()
        .collect(Collectors.groupingBy(
                Employee::getDept,
                Collectors.summarizingDouble(Employee::getSalary)
        ));

statsByDept.forEach((dept, st) -> {
    System.out.printf("部门: %s, 人数: %d, 平均工资: %.2f%n",
            dept, st.getCount(), st.getAverage());
});

这种写法只遍历一次集合,就把分组和每组的多项统计全部完成了,性能和可读性都不错。如果只需要平均值,用 Collectors.averagingDouble 就够了;但如果同时需要多份数据,与其重复遍历多次流,不如直接用 summarizingDouble 一次拿全。

使用注意事项

第一,精度问题。DoubleSummaryStatistics 内部使用 double 累加,对于精度敏感的场景(比如金融金额计算),累积误差不可避免。如果业务对精度要求高,可以考虑先转换成 BigDecimal 处理,或者对统计结果的展示位数做好控制。

第二,并行流的合并。这个类是非线程安全的,单独多个线程共享同一个实例调用 accept 会有问题。但在并行流中使用 collect 是安全的,因为流框架会为每个线程创建独立实例,最后通过 combine 合并,这正是它实现 DoubleConsumer 和提供 combine 方法的设计意图。

第三,同类工具的选择。JDK 中还有 IntSummaryStatistics 和 LongSummaryStatistics,分别对应 int 和 long 类型的统计,用法完全一样。如果数据本身是整数类型,用对应的版本可以避免不必要的装箱和精度转换。另外 DoubleStream 上还有 average()max() 等单独方法,适合只需要一项数据的简单场景。

总结一下,DoubleSummaryStatistics 适合任何需要一次性获取多项数值统计的场景,核心记住两点:空数据时 min、max、average 的返回值比较特殊,需要先判断 count;和 groupingBy 组合可以实现高效的分组统计。掌握这些,日常处理数据统计的代码会简洁很多。

DoubleSummaryStatisticsJava Streamcollect修改时间:2026-09-07 18:04:35

免责声明:已尽一切努力确保本网站所含信息的准确性。网站作品多为原创整理与精心创作,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们进行处理Email:chomcom@qq.com。
引用或转载本作品时,请注明当前出处:https://www.ipipp.com/html/20260907/52363.html,基于非商业用途的前提下,欢迎转载或二创本作品。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。