You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在单次Java Stream中同时过滤对象并统计不同条件实例数

单次Stream操作完成双需求的实现方案

当然可以在单次Stream遍历中完成这两个需求,不用两次遍历列表。核心是在遍历每个元素时同时判断两个条件,分别更新筛选列表和计数器。下面给两种常用实现方式:

方法一:自定义Collector(推荐,适配并行流)

先定义一个用来存储结果的简单类,把筛选列表和计数器封装进去:

class ProcessResult {
    private final List<MyClass> filteredItems = new ArrayList<>();
    private int nonXAndZCount = 0;

    // 处理单个元素的逻辑
    public void accept(MyClass item) {
        if (item.isX() && item.isY()) {
            filteredItems.add(item);
        } else if (!item.isX() && item.isZ()) {
            nonXAndZCount++;
        }
        // 不满足条件的元素直接跳过
    }

    // 并行流时合并多个结果容器
    public ProcessResult merge(ProcessResult other) {
        this.filteredItems.addAll(other.filteredItems);
        this.nonXAndZCount += other.nonXAndZCount;
        return this;
    }

    // 获取结果的方法
    public List<MyClass> getFilteredItems() {
        return filteredItems;
    }

    public int getNonXAndZCount() {
        return nonXAndZCount;
    }
}

然后用Stream的collect方法来使用这个类:

ProcessResult result = myClasses.stream()
    .collect(
        ProcessResult::new,  // 创建结果容器
        ProcessResult::accept,  // 处理每个元素
        ProcessResult::merge  // 合并并行处理的结果
    );

List<MyClass> filteredClasses = result.getFilteredItems();
int isNotXandZCounter = result.getNonXAndZCount();

这种方式完全符合Stream的设计规范,并行流场景下也不需要额外做线程同步,Collector会自动处理结果合并。

方法二:用容器变量直接处理(简洁,串行流友好)

如果不想额外定义类,可以用数组或者原子类来包装计数器(因为lambda里不能修改基本类型变量),配合列表一起处理:

List<MyClass> filteredList = new ArrayList<>();
int[] counter = {0};  // 用数组包装int,让lambda能修改值

myClasses.stream().forEach(item -> {
    if (item.isX() && item.isY()) {
        filteredList.add(item);
    } else if (!item.isX() && item.isZ()) {
        counter[0]++;
    }
});

要是用并行流的话,得注意线程安全,换成同步列表和原子计数器就行:

List<MyClass> filteredList = Collections.synchronizedList(new ArrayList<>());
AtomicInteger counter = new AtomicInteger(0);

myClasses.parallelStream().forEach(item -> {
    if (item.isX() && item.isY()) {
        filteredList.add(item);
    } else if (!item.isX() && item.isZ()) {
        counter.incrementAndGet();
    }
});

另外提一句:你原来的代码里filter(MyClass::isX() && MyClass::isY())是语法错误,正确写法应该是filter(item -> item.isX() && item.isY()),方法引用不能直接用逻辑运算符组合。

内容的提问来源于stack exchange,提问作者artificialdeathinthewest

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 06:00:29