使用身份组合器的并行流降低

3
final Stream<Integer> numbers = Stream.of(5, 3, 2, 7, 3, 13, 7).parallel();

为什么下面这行代码的输出结果是7?
 numbers.reduce(1, (a, b) -> a + b, (x, y) -> x - y)); 

2
您正在违反reduce的契约,因为1不是您的累加器/组合器的标识。请参见javadoc - Misha
为什么它不是一个身份证?请查看此代码- http://www.concretepage.com/java/jdk-8/java-8-stream-reduce-example(ReduceDemo3) - Chlebik
1
那个链接有一些问题,因为它违反了一些属性;请阅读文档而不是那个。 - Eugene
2
任何人都可以建立一个网页。而且有很多这样的网页,它们不会告诉你比官方教程API文档更多的信息。但是你链接的那个页面是最糟糕的之一,它的内容非常错误。也许这个问答能够帮到你…… - Holger
1个回答

4
我还没有查看评论中的链接,但是文档已经非常清楚地说明了identity,并且它甚至提供了一种简单的测试方法:

标识值必须是组合函数的标识。这意味着对于所有的u,combiner(identity, u)等于u。

因此,让我们简化一下你的例子:
Stream<Integer> numbers = Stream.of(3, 1).parallel();
BiFunction<Integer, Integer, Integer> accumulator = (a, b) -> a + b;

BiFunction<Integer, Integer, Integer> combiner = (x, y) -> x - y; 

    int result = numbers.reduce(
            1,
            accumulator,
            combiner);

    System.out.println(result);

假设 u = 3(仅为来自流的随机元素),因此:

    int identity = 1;
    int u = 3;

    int toTest = combiner.apply(identity, u);
    System.out.println(toTest == identity); // must be true, but is false

即使您认为您可以用替换身份,这也是可行的;然而文档提出了另一个观点:

此外,组合函数必须与累加器函数兼容。对所有的和t,以下条件必须成立:

 combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

您可以进行相同的测试:
int identity = 0;
int u = 3;
int t = 1;

boolean associativityRespected = 
     combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t);
System.out.println(associativityRespected); // prints false

2
换句话说,在reduce中执行两个完全不同的操作,比如(a,b)->a+b(x,y)->x-y是没有意义的。此外,(x, y) -> x - y本身就违反了契约,因为它不是可结合的。令人印象深刻的是,那个网页的作者在一个例子中竟然放了这么多错误的东西... - Holger
@Holger,我只能说,在需要将一些代码移植到Java-8的位置时(而且经理们完全不知道它确实需要相当多的时间来理解这些东西),在网上找到一个好的资源真的很难。所以,是的,我非常同意。很高兴你在身边,显然。 - Eugene
在你的第一次测试中,我猜你想表达的是 System.out.println(toTest == u); - Thiyagu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接