是否不能保证从列表派生的并行流始终像其顺序对应的对象一样提供可预测的相同输出呢?

Tre*_*ang 6 java java-8 java-stream

下面的代码将true打印100次:

for(int i=0; i<100; i++) {
   String s2 = Arrays.asList("A", "E", "I", "O", "U").parallelStream().reduce("x", String::concat, String::concat);
   System.out.println("xAxExIxOxU".equals(s2));
}
Run Code Online (Sandbox Code Playgroud)

当然,不能保证100次。但是,即使文档中使用的标识不满足“ ...对于所有u,combiner.apply(identity,u)等于u”的要求,我们似乎仍然可以说a从列表或任何其他固有排序结构派生的并行流的行为就像reduce()中的顺序流返回相同的输出?

Erw*_*idt 4

带有标识参数的函数的 JavadocStream.reduce说:

标识值必须是累加器函数的标识。这意味着对于所有 t,accumulator.apply(identity, t) 等于 t。

显然这里的情况并非如此——"x".concat(anything)不等于anything。这里唯一有效的身份值是""

如果您测试了问题标题的前提- 通过查看非并行操作返回的内容 - 您会发现标题的答案是“否” - 因为非并行流"xAEIOU"为您的归约操作返回。

如果您将标识值从 更改为"x"""那么答案将是“是的,有这样的保证,因为您的reduce 函数是关联的并且也满足标识值的约束。”

即使您修改了标题,答案也很明确:

reduce通过提供一个不是您的reduce函数的身份值的值作为身份值,您违反了函数的契约。因此,由于您违反了方法的合同reduce,所有保证都将被取消。

很容易创建一个不成立的案例;就像霍尔格已经指出的那样,让你的清单更大:

List<String> list = new ArrayList<>();
for (int i = 0; i < 500; i++) {
    list.add("A");
}
String s2 = list.parallelStream().reduce("x", String::concat, String::concat);
System.out.println(s2);
if (s2.length() != list.size() * 2) {
    System.out.println("Bad s2 size");
}
Run Code Online (Sandbox Code Playgroud)

  • @TreefishZhang 现在你问了一个非常不同的问题。我没有指出你标题中的任何问题,我只是回答你最初提出的问题。 (5认同)