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

为何Java 8 Stream的reduce方法不同合并函数返回结果一致?

为什么不同的reduce合并函数返回相同结果?

先看你给出的Java代码:

public static void main(String... aa) {
    Stream<Integer> stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
    List<Integer> numbers = stream.reduce(
            new ArrayList<Integer>(),
            (List<Integer> l, Integer e) -> {
                l.add(e);
                return l;
            },
            (List<Integer> l1, List<Integer> l2) -> {
                l1.addAll(l2);
                return l1;
            });
    System.out.println("numbers" + numbers);

    stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
    numbers = stream.reduce(new ArrayList<Integer>(),
            (List<Integer> l, Integer e) -> {
                l.add(e);
                return l;
            },
            (List<Integer> l1, List<Integer> l2) -> {
                return l1;
            });
    System.out.println("numbers" + numbers);

    stream = Arrays.asList(1, 2, 3, 4, 5, 6).stream();
    numbers = stream.reduce(new ArrayList<Integer>(),
            (List<Integer> l, Integer e) -> {
                l.add(e);
                return l;
            },
            (List<Integer> l1, List<Integer> l2) -> {
                return null;
            });
    System.out.println("numbers" + numbers);
}

执行后输出结果均为:

numbers[1, 2, 3, 4, 5, 6]
numbers[1, 2, 3, 4, 5, 6]
numbers[1, 2, 3, 4, 5, 6]

核心原因:串行流不会触发合并函数

你这里用的是串行流(stream()),在串行流的执行逻辑里,reduce的合并函数(第三个参数)完全不会被调用。

串行流的处理流程是:从初始的ArrayList开始,逐个把元素通过累加器(第二个参数)添加到同一个列表里,全程不需要拆分任务,自然也就不需要合并多个中间结果。所以不管你把合并函数写成什么逻辑,都不会影响最终结果——因为它根本没被执行过。

并行流才会用到合并函数

如果把代码里的stream()改成parallelStream()(并行流),情况就完全不同了:

  • 第一个例子的合并函数正常合并两个列表,结果还是完整的[1,2,3,4,5,6](元素顺序可能因为并行处理发生变化)。
  • 第二个例子的合并函数只返回第一个列表,会丢失第二个子任务处理的元素,结果可能是[1,2,3]或其他不完整的列表(具体取决于任务拆分方式)。
  • 第三个例子的合并函数返回null,在合并阶段会直接抛出NullPointerException,因为无法用null完成结果合并。

额外提醒:你的累加器写法有问题

顺便提一句,你这里的累加器直接修改传入的初始列表,不符合reduce的设计规范——reduce的累加器应该是无副作用的,即不修改输入参数,而是返回新的对象。如果在并行流里这么写,会因为多个线程同时修改同一个列表导致并发问题。正确的写法应该是每次返回新列表:

(List<Integer> l, Integer e) -> {
    List<Integer> newList = new ArrayList<>(l);
    newList.add(e);
    return newList;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 01:50:27