如何使用Java Stream的reduce方法累加Stopwatch列表的总Duration时长
用Stream的reduce方法统计报表总耗时
我明白你想把原来的循环累加逻辑改成Stream的reduce实现,刚好你的场景很适合用Stream API来简化代码。先回顾下你的基础代码:
你的Stopwatch类定义:
public class Stopwatch { public String report; public Instant startTime; public Instant endTime; public Duration duration; }
原来的循环累加逻辑:
Duration total = Duration.ZERO; for (Stopwatch s: _reportStats) { total = total.plus(s.duration); }
推荐的Stream reduce写法
最贴合你原有逻辑的写法是带初始值的reduce重载,因为你本来就用Duration.ZERO作为初始累加值,这种写法直接对应你的循环逻辑:
Duration total = _reportStats.stream() .map(Stopwatch::getDuration) // 先将每个Stopwatch映射为它的duration属性 .reduce(Duration.ZERO, Duration::plus);
如果你不想单独用map步骤,也可以把逻辑合并到reduce里:
Duration total = _reportStats.stream() .reduce(Duration.ZERO, (accumulator, stopwatch) -> accumulator.plus(stopwatch.duration), Duration::plus);
代码解释
- 第一个参数
Duration.ZERO:就是你原来代码里的初始累加值,确保即使列表为空,也能返回合法的Duration对象(不会出现null) - 第二个参数(累加器):定义了如何把当前的累加结果和单个
Stopwatch的duration相加,和你循环里的total = total.plus(s.duration)完全一致 - 第三个参数(组合器):用于并行流场景下合并不同线程的累加结果,这里直接用
Duration::plus就可以,因为Duration的加法是线程安全的;如果是串行流,这个参数不会被实际调用,但语法上必须提供
可选的另一种写法(处理空列表)
如果你想显式处理列表为空的情况,也可以用不带初始值的reduce,它会返回Optional<Duration>,这时你需要用orElse指定默认值:
Optional<Duration> totalOptional = _reportStats.stream() .map(Stopwatch::getDuration) .reduce(Duration::plus); Duration total = totalOptional.orElse(Duration.ZERO);
不过这种写法需要额外处理Optional,不如第一种写法简洁,毕竟你的原有逻辑就是默认初始为ZERO,不管列表有没有元素都返回一个Duration对象。
内容的提问来源于stack exchange,提问作者rupweb
相关产品推荐
相关产品推荐

