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

能否将Java8 Stream中求和、统计非零数、求均值三步合并为一步?

当然可以!完全能把这三个步骤合并成一次Stream遍历,这样效率更高(不用多次遍历组件列表),还能把相关逻辑整合在一起,代码更紧凑。

方案1:Java 12+ 使用 Collectors.teeing

Java 12引入的teeing收集器正好适配这种场景——它会把每个元素同时传递给两个下游收集器,最后将两个收集器的结果合并成最终值。这里我们用一个收集器计算总成本,另一个过滤非零价格后统计数量,最后计算平均值:

private double calculateTotalBCMMatrixCost(SpecificationEntryRequest specificationEntryRequest) {
    return specificationEntryRequest.getComponentList().stream()
            .map(ComponentDetail::getStartingMaterialId)
            .map(this::calculateBCMMatrixCostForAnalyte)
            .collect(Collectors.teeing(
                    // 第一个收集器:计算总成本
                    Collectors.summingDouble(Double::doubleValue),
                    // 第二个收集器:统计非零价格的数量
                    Collectors.filtering(price -> price > 0, Collectors.counting()),
                    // 合并结果:计算平均值(处理除数为0的边界情况)
                    (totalCost, nonZeroCount) -> nonZeroCount == 0 ? 0.0 : totalCost / nonZeroCount
            ));
}

方案2:Java 12以下版本 自定义收集容器

如果你的项目还在使用Java 12之前的版本,可以自定义一个简单的容器类,在一次遍历中同时累加总和和非零计数:

// 自定义容器类,用于存储总和和非零数量
private static class CostStats {
    double total = 0.0;
    long nonZeroCount = 0;

    // 处理单个价格
    void accept(double price) {
        total += price;
        if (price > 0) {
            nonZeroCount++;
        }
    }

    // 合并多个容器(并行流场景下需要)
    CostStats combine(CostStats other) {
        this.total += other.total;
        this.nonZeroCount += other.nonZeroCount;
        return this;
    }
}

private double calculateTotalBCMMatrixCost(SpecificationEntryRequest specificationEntryRequest) {
    CostStats stats = specificationEntryRequest.getComponentList().stream()
            .map(ComponentDetail::getStartingMaterialId)
            .map(this::calculateBCMMatrixCostForAnalyte)
            .collect(CostStats::new, CostStats::accept, CostStats::combine);

    // 同样处理除数为0的情况,避免运行时异常
    return stats.nonZeroCount == 0 ? 0.0 : stats.total / stats.nonZeroCount;
}

额外提示

原代码存在一个潜在问题:如果所有价格都是0,nonZeroPriceCount会是0,直接做除法会抛出ArithmeticException。上面的两种方案都加入了边界处理,你可以根据业务需求调整(比如返回0、抛出自定义异常等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 17:53:10