Java Stream 减少无法解释的行为

标签 java java-8 java-stream reduce

谁能给我指出正确的方向,因为我无法理解这个问题。

我正在执行以下方法。

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    List<String> join = vals.parallelStream().reduce(new ArrayList<String>(),
            (List<String> l, String v) -> {

                l.add(v);

                return l;
            }, (a, b) -> {                   
                a.addAll(b);
                return a;
            }

    );

   System.out.println(join);

}

它打印

[null, a, null, a]

我不明白为什么它会在结果列表中放置两个 null。我希望答案是

[a, b]

因为是并行流所以第一个参数要减少

new ArrayList()

可能会为每个输入值 a 和 b 调用两次。

然后累加器函数可能会被调用两次,因为它是一个 parallelStream 并在每次调用中传递每个输入“a 和 b”以及种子值提供的列表。所以 a 被添加到列表 1,b 被添加到列表 2(反之亦然)。之后,组合器将合并两个列表,但并没有发生。

有趣的是,如果我在累加器中放置一个打印语句来打印输入值,输出就会改变。所以下面

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    List<String> join = vals.parallelStream().reduce(new ArrayList<String>(),
            (List<String> l, String v) -> {
                System.out.printf("l is %s", l);
                l.add(v);
                System.out.printf("l is %s", l);
                return l;
            }, (a, b) -> {
                a.addAll(b);
                return a;
            }

    );

   System.out.println(join);

}

此输出的结果

l is []l is [b]l is [b, a]l is [b, a][b, a, b, a]

谁能解释一下。

最佳答案

在使用 parallelStream() 时,您应该使用 Collections.synchronizedList()。因为 ArrayList 不是线程安全的,当您并发访问它时会出现意想不到的行为,就像您使用 parallelStream() 一样。

我已经修改了你的代码,现在它可以正常工作了:

private static void reduce_parallelStream() {
    List<String> vals = Arrays.asList("a", "b");

    // Use Synchronized List when with parallelStream()
    List<String> join = vals.parallelStream().reduce(Collections.synchronizedList(new ArrayList<>()),
            (l, v) -> {
                l.add(v);
                return l;
            }, (a, b) -> a // don't use addAll() here to multiplicate the output like [a, b, a, b]
    );
    System.out.println(join);
}

输出:

有时你会得到这样的输出:

[a, b]

有时这个:

[b, a]

原因是它是一个 parallelStream(),因此您无法确定执行顺序。

关于Java Stream 减少无法解释的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58006434/

相关文章:

lambda - 如何获取由 lambda 产生的方法的名称

java - 使用 Java8 流在 Java 集合中查找给定值最接近的对象

Java Map<String,String[]> 如何对值求和

java - slf4j 依赖项破坏 log4j 配置的问题

java - 在 Red Hat 服务器中找不到 JAVA_HOME

java - java中的多个catch语句

java - ifPresent Stream 的 Else 方法

java - 不支持的 Java 版本 : Cannot start under Java 1. 7 : Java 1. 需要 8 或更高版本

sorting - 根据两个日期(创建日期和更新日期)对记录的对象列表进行排序

java - Iterables.partition() 生成的 Spliterator 没有按预期运行?