Java Stream中如何同时实现过滤元素的打印与计数?
在单个Stream中同时实现过滤元素的打印与计数
针对你的需求,有几种优雅的单遍历解决方案,能避免重复执行耗时的过滤逻辑:
方法一:使用AtomicLong计数器(简单直观)
借助原子类在forEach中同时完成打印和计数,线程安全且适用于并行流:
import java.util.concurrent.atomic.AtomicLong; // 初始化计数器 AtomicLong counter = new AtomicLong(); someList.stream() .filter(s -> predicate1()) .filter(s -> predicate2()) .forEach(s -> { System.out.println(s); counter.incrementAndGet(); }); // 获取最终计数 long counted = counter.get();
这种方式代码简洁,容易理解,适合大多数日常场景。
方法二:使用reduce操作(函数式风格)
利用Stream的reduce方法,将元素处理与计数逻辑整合到累加器中:
long counted = someList.stream() .filter(s -> predicate1()) .filter(s -> predicate2()) .reduce(0L, (count, s) -> { System.out.println(s); return count + 1; }, Long::sum);
这里的reduce接受三个参数:初始计数0L、处理每个元素的累加器(打印并计数+1)、并行流时的计数合并函数。完全基于Stream API实现,无需额外对象。
方法三:自定义Collector(高复用性)
如果需要复用这个"打印+计数"的逻辑,可以自定义Collector,封装完整的处理流程:
import java.util.stream.Collector; import java.util.concurrent.atomic.AtomicLong; // 自定义Collector Collector<String, ?, Long> printAndCountCollector = Collector.of( AtomicLong::new, // 供应器:创建计数器 (counter, s) -> { // 累加器:打印元素并递增计数 System.out.println(s); counter.incrementAndGet(); }, (leftCounter, rightCounter) -> { // 组合器:并行流时合并计数 leftCounter.addAndGet(rightCounter.get()); return leftCounter; }, AtomicLong::get // 终止器:获取最终计数值 ); // 使用Collector long counted = someList.stream() .filter(s -> predicate1()) .filter(s -> predicate2()) .collect(printAndCountCollector);
这种方式适合需要多次使用相同逻辑的场景,封装性更强,符合面向对象的设计思想。
以上三种方案都只遍历集合一次,避免了重复执行过滤逻辑带来的性能损耗,根据你的实际场景选择即可。
内容的提问来源于stack exchange,提问作者jakub_k
相关产品推荐
相关产品推荐

