reduce概念
下面解释是抄别人的。和haskell
等语言里的概念很像
好的命名是自解释的 reduce的方法取得就是其中归纳的含义 java8 流相关的操作中,我们把它理解
“累加器”,之所以加引号是因为他并不仅仅是加法 他的运算可以是一个Lambda 表达式 所以更准确的说 reduce 是一个迭代运算器
Stream包的文档中其实已经说的很明白了 但是就是因为不是很理解所以看的云里雾里 其中说到:
一个reduce操作(也称为折叠)接受一系列的输入元素,并通过重复应用操作将它们组合成一个简单的结果
并发的问题
函数介绍
- reduce(accumulator)
- reduce(identity,accumulator)
- reduce(identity,accumulator,combiner)
identity
是reduce
进行迭代操作的初始值。accumulator
是用来迭代的。combiner
是并发时用来合并各线程结果的。
代码
public class AppTest {
/**
* Rigorous Test :-)
*/
@Test
public void test2() {
assertTrue(true);
int b = Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(0, (acc, x) -> acc + x);
int c = Stream.of(2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(1, (acc, x) -> acc + x);
int d = Stream.of(2, 3, 4, 5, 6, 7, 8, 9).parallel().reduce(1, (acc, x) -> acc + x, (x, y) -> x + y - 1);
System.out.printf("初始值个数不影响结果:%d\n", b);
System.out.printf("无修正:%d\n", c);
System.out.printf("合并修正:%d\n", d);
}
}
结果
可以明显看到第二个方式是有问题的。原因是初始值加了四遍。这是由于他内部是使用了fork-join框架
把大任务转小任务,然后并发运行。有点像归并排序的感觉。但是为了保证并发安全,他把每个输入数据都复制了一份,这样自然不用🔓了,但同时导致初始值多加三遍。所以redue源代码注释里才会有这句话。
combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)
和这句话
combiner(identity, u) is equal to u
这两句话只要满足一个就行了。
在这个例子里,初始值为0当然是符合的,为1 是不符合的。
我们这里可以把思维再扩展些。这里的等于并不是要求地址相等是同一个对象,而只是要求逻辑上等价。
话说这也太卷了,我就做个累加也要并发。😃