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

如何使用Stream API筛选出大于平均值的元素?能否不使用两次流、仅借助Collectors类实现该需求?

如何用单次流操作提取大于算术平均值的整数列表?

嘿,我懂你现在的需求!你当前的代码用了两次流操作来实现——先算平均值,再过滤出大于平均值的元素,但确实可以优化成只遍历一次源集合,而且完全能借助Collectors类的方法来完成,不用自己写太多复杂逻辑。

先说说为什么两次流不太理想:如果你的整数集合很大,两次遍历会额外消耗不少性能,毕竟遍历一次和两次的时间复杂度差了一倍呢。下面给你两种靠谱的解决方案,分Java版本来看:

方案一:用Java 12+的Collectors.teeing()(推荐)

Java 12引入的teeing收集器简直为这种场景量身定做!它能把流中的每个元素同时传递给两个不同的收集器,最后再把这两个收集器的结果合并成你想要的最终结果。这样整个过程只需要遍历一次源集合。

代码示例:

List<Integer> aboveAverage = values.stream()
    .collect(Collectors.teeing(
        // 第一个收集器:计算集合的算术平均值
        Collectors.averagingInt(Integer::intValue),
        // 第二个收集器:把所有元素收集到列表里
        Collectors.toList(),
        // 合并函数:用第一个收集器得到的平均值过滤第二个收集器的列表
        (average, allElements) -> allElements.stream()
            .filter(num -> num > average)
            .collect(Collectors.toList())
    ));

这个写法既简洁又高效,完全符合你的要求——只用一次流,全程依赖Collectors类的方法。

方案二:自定义Collector(兼容Java 8及以上)

如果你的项目还在用Java 8或者更低版本,没法用teeing,那可以自定义一个Collector,在一次遍历中同时记录总和、元素个数以及所有元素,最后再计算平均值并过滤出符合条件的元素。

自定义Collector的代码如下:

import java.util.*;
import java.util.stream.Collector;
import static java.util.stream.Collector.Characteristics;

class AboveAverageCollector implements Collector<Integer, Map<String, Object>, List<Integer>> {
    @Override
    public Supplier<Map<String, Object>> supplier() {
        // 初始化容器:保存总和、元素个数、所有元素
        return () -> {
            Map<String, Object> container = new HashMap<>();
            container.put("sum", 0);
            container.put("count", 0);
            container.put("elements", new ArrayList<>());
            return container;
        };
    }

    @Override
    public BiConsumer<Map<String, Object>, Integer> accumulator() {
        // 累加阶段:更新总和、计数,同时添加元素到列表
        return (container, num) -> {
            container.put("sum", (int) container.get("sum") + num);
            container.put("count", (int) container.get("count") + 1);
            ((List<Integer>) container.get("elements")).add(num);
        };
    }

    @Override
    public BinaryOperator<Map<String, Object>> combiner() {
        // 并行流场景下合并两个容器的结果
        return (container1, container2) -> {
            container1.put("sum", (int) container1.get("sum") + (int) container2.get("sum"));
            container1.put("count", (int) container1.get("count") + (int) container2.get("count"));
            ((List<Integer>) container1.get("elements")).addAll((List<Integer>) container2.get("elements"));
            return container1;
        };
    }

    @Override
    public Function<Map<String, Object>, List<Integer>> finisher() {
        // 完成阶段:计算平均值,过滤出大于平均值的元素
        return container -> {
            double average = (int) container.get("sum") / (double) (int) container.get("count");
            return ((List<Integer>) container.get("elements")).stream()
                    .filter(num -> num > average)
                    .collect(Collectors.toList());
        };
    }

    @Override
    public Set<Characteristics> characteristics() {
        return Collections.emptySet();
    }
}

使用的时候直接调用:

List<Integer> aboveAverage = values.stream().collect(new AboveAverageCollector());

这个自定义Collector也能做到单次遍历,而且兼容低版本Java。

对比你原来的写法,这两种方案都避免了两次遍历集合的问题,性能上更优,也完全满足你借助Collectors类实现的需求~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 13:54:06