怎么利用 IntStream.summaryStatistics() 一次性获取整数序列的均值、极值与总和
怎么利用 IntStream.summaryStatistics() 一次性获取整数序列的均值、极值与总和

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
在Ja va的流式编程中,IntStream.summaryStatistics() 方法堪称一个“统计多面手”。它返回一个包含计数、总和、最小值、最大值和平均值的对象。这里有个关键细节:对于空流,getMin() 和 getMax() 会抛出 NoSuchElementException,而 getA verage() 会返回 NaN,getSum() 和 getCount() 则返回0。理解这些行为,是安全使用它的第一步。
IntStream.summaryStatistics() 能返回哪些统计值
调用 IntStream.summaryStatistics() 会得到一个 IntSummaryStatistics 实例。这个对象内部巧妙地缓存了五个核心统计量:计数、总和、最小值、最大值以及平均值(注意,平均值是 double 类型)。关键在于,这些值并非实时计算,而是在流遍历过程中一次性累积完成的。这意味着,你无需为了获取总和、最大值和平均值而分别调用 sum()、max()、a verage() 等终端操作,从而避免了多次遍历流的性能开销。
必须注意的空流陷阱
空流是许多统计操作的“暗礁”,summaryStatistics() 也不例外。如果流中没有任何元素,那么调用 getMin() 和 getMax() 将直接抛出 NoSuchElementException。与此同时,getA verage() 会返回一个特殊的 NaN(Not a Number),而 getSum() 和 getCount() 则规规矩矩地返回0。这并非程序缺陷,而是API的明确设计。
- 首要检查:务必在调用
getMin()或getMax()之前,先判断getCount() > 0。 - 平均值处理:不要直接对
getA verage()的返回值进行算术运算(比如加1),应该先用Double.isFinite()等方法判断其是否为有效数值。 - 默认值策略:若业务逻辑要求为空流提供默认值,建议使用
Optional.ofNullable(...).orElse(...)这类模式进行封装,这比硬编码 try-catch 块更加优雅和清晰。
和单独调用 min()/max()/a verage() 的性能差异
性能考量往往是选择的关键。如果分别调用 min()、max()、a verage(),每个终端操作都会触发一次独立的流遍历,时间复杂度是 O(3n)。而 summaryStatistics() 只需遍历一次,时间复杂度为 O(n),并且其内部对象创建的开销微乎其微。这种差异在并行流场景下会被进一步放大——并行流中的 summaryStatistics() 能够自动合并各个分段的统计结果,而多次单独的终端操作则可能因为流已被消费关闭而抛出 IllegalStateException。
- 适用场景:当你需要同时获取三个或以上聚合统计值时,它就是最佳选择。
- 不适用场景:如果仅仅需要最大值或平均值等单一指标,直接调用对应方法语义更清晰,并且JIT编译器可能进行更有效的优化。
- 并行流提示:在并行流下,
IntSummaryStatistics的toString()方法输出的字段顺序可能不固定,但请放心,每个字段的数值本身都是准确无误的。
一个安全可用的实操示例
理论说得再多,不如一段健壮的代码来得实在。下面这个示例能安全处理任意 int[] 数组,包括空数组,并显式防御了所有边界情况:
int[] data = {1, 3, 2, 5};
IntSummaryStatistics stats = IntStream.of(data).summaryStatistics();
if (stats.getCount() == 0) {
System.out.println("空数据");
} else {
System.out.printf("count=%d, sum=%d, min=%d, max=%d, a vg=%.2f%n",
stats.getCount(),
stats.getSum(),
stats.getMin(),
stats.getMax(),
stats.getA verage()
);
}
最后提个醒:平均值是 double 类型,在格式化输出时很容易忽略精度问题。如果下游逻辑需要一个整数形式的均值,应当明确使用 (int) Math.round(stats.getA verage()) 进行四舍五入,而不是简单地强制类型转换进行截断,这能避免精度损失带来的潜在错误。
相关攻略
怎么区分 Stream 流的并行处理 parallel() 与普通处理在底层线程池(ForkJoinPool)的共用 简单来说,并行流的 parallel() 并不创建新线程池,而是直接复用 JVM 全局共享的 ForkJoinPool commonPool()。普通流(stream())则完全是另
怎么利用 IntStream summaryStatistics() 一次性获取整数序列的均值、极值与总和 在Ja va的流式编程中,IntStream summaryStatistics() 方法堪称一个“统计多面手”。它返回一个包含计数、总和、最小值、最大值和平均值的对象。这里有个关键细节:对于
11 月 11 日消息,海盗船旗下 Elgato 德国当地时间 10 日宣布推出 Discord 特别版 Stream Deck Mini。这款拥有六个可自定义 LCD 按键的直播控台采用了 Di
热门专题
热门推荐
MongoDB 3 6旧版本如何平滑迁移GridFS数据 在MongoDB 3 6版本中,使用mongodump进行数据备份时,默认会忽略GridFS存储所使用的fs files和fs chunks集合,因为它们被系统视为内部命名空间。为确保GridFS文件数据的完整迁移,必须显式指定导出这两个集合
生产环境禁用 KEYS+DEL,因其会阻塞 Redis 主线程;应使用带游标和分批的 SCAN+DEL Lua 脚本或 Ja va 中通过 RedisConnection 执行 SCAN 迭代删除,避免连接泄漏。 直接使用 KEYS 配合 DEL 来批量删除特定前缀的 Key,听起来很直接,对吧?但
Redis为什么会出现内存泄漏的假象?排查Lua脚本中未设置过期的临时变量 Redis内存持续上涨可能源于Lua脚本中未设置过期时间的临时键,如set、hset、zadd写入后遗漏expire,导致“孤儿键”累积;需用redis-cli --scan结合object freq和ttl定位,并按业务语
多级分组排名应选rank()或dense_rank()而非row_number():rank()跳过重复名次,dense_rank()连续编号;必须配合PARTITION BY和ORDER BY,且WHERE筛选需用子查询避免破坏分组。 rank() 和 dense_rank() 在多级分组中行为差
Redis如何实现基于发布订阅的配置热更新 Redis Pub Sub 能否可靠用于配置热更新? 直接拿来用?恐怕不行。Redis 的 PUBLISH SUBSCRIBE 本质上是一种“即发即弃”的模型:消息不持久、没有确认机制、订阅者离线期间的消息会彻底丢失。想象一下,你的服务因为重启或者网络短暂





