Lou*_*ler 123 java java-8 java-stream
我无法完全理解combiner
Streams reduce
方法中实现的角色.
例如,以下代码不编译:
int length = asList("str1", "str2").stream()
.reduce(0, (accumulatedInt, str) -> accumulatedInt + str.length());
Run Code Online (Sandbox Code Playgroud)
编译错误说:( 参数不匹配; int无法转换为java.lang.String)
但是这段代码确实编译:
int length = asList("str1", "str2").stream()
.reduce(0, (accumulatedInt, str ) -> accumulatedInt + str.length(),
(accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2);
Run Code Online (Sandbox Code Playgroud)
我知道组合器方法用于并行流 - 所以在我的例子中它将两个中间累积的int加在一起.
但是我不明白为什么第一个例子在没有组合器的情况下编译或者组合器如何解决字符串到int的转换,因为它只是将两个整数加在一起.
任何人都可以阐明这一点吗?
Stu*_*rks 193
Eran的答案描述了两个arg和三个arg版本之间的差异reduce
,前者减少Stream<T>
到T
后者,而后者减少Stream<T>
到U
.但是,它实际上并没有解释的附加功能组合的需求减少时Stream<T>
至U
.
Streams API的设计原则之一是API在顺序流和并行流之间不应该有所区别,换句话说,特定的API不应该阻止流顺序或并行地正确运行.如果你的lambdas具有正确的属性(关联,非干扰等),顺序或并行运行的流应该给出相同的结果.
让我们首先考虑减少的两个arg版本:
T reduce(I, (T, T) -> T)
Run Code Online (Sandbox Code Playgroud)
顺序实现很简单.I
使用第0个流元素"累积" 标识值以给出结果.该结果与第一流元素一起累积以给出另一结果,该结果又与第二流元素一起累积,等等.累积最后一个元素后,返回最终结果.
并行实现通过将流拆分为段来开始.每个段由其自己的线程以上述顺序方式处理.现在,如果我们有N个线程,我们有N个中间结果.这些需要减少到一个结果.由于每个中间结果都是T类型,并且我们有几个,我们可以使用相同的累加器函数将这些N个中间结果减少到单个结果.
现在让我们考虑一个假设的两个arg减少操作,减少Stream<T>
到U
.在其他语言中,这称为"折叠"或"向左折叠"操作,因此我将在此处称之为"折叠"或"向左折叠"操作.请注意,这在Java中不存在.
U foldLeft(I, (U, T) -> U)
Run Code Online (Sandbox Code Playgroud)
(请注意,标识值I
的类型为U.)
顺序版本foldLeft
就像顺序版本一样,reduce
只是中间值是U型而不是T型.但它在其他方面是相同的.(假设foldRight
操作类似,只是操作将从右到左而不是从左到右执行.)
现在考虑并行版本foldLeft
.让我们从将流分割成段开始.然后我们可以让N个线程中的每个线程将其段中的T值减少为U类型的N个中间值.现在是什么?我们如何从U类型的N值到U类型的单个结果?
缺少的是将 U类型的多个中间结果组合成U类型的单个结果的另一个函数.如果我们有一个将两个U值组合成一个的函数,那就足以将任意数量的值减少到一个 - 就像原来的减少在上面.因此,给出不同类型结果的缩减操作需要两个函数:
U reduce(I, (U, T) -> U, (U, U) -> U)
Run Code Online (Sandbox Code Playgroud)
或者,使用Java语法:
<U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
Run Code Online (Sandbox Code Playgroud)
总之,要对不同的结果类型进行并行缩减,我们需要两个函数:一个将T元素累积到中间U值,另一个将中间U值组合成单个U结果.如果我们不切换类型,则结果是累加器函数与组合器函数相同.这就是为什么减少到相同类型只有累加器功能和减少到不同类型需要单独的累加器和组合器功能.
最后,Java不提供foldLeft
和foldRight
操作,因为它们暗示了本质上顺序的特定操作顺序.这与上述设计原则相冲突,即提供支持顺序和并行操作的API.
Lui*_*ese 97
因为我喜欢涂鸦和箭头来澄清概念......让我们开始吧!
假设有4个字符串:你的目标是将这些字符串连接成一个字符串.你基本上从一个类型开始,并以相同的类型完成.
你可以实现这一目标
String res = Arrays.asList("one", "two","three","four")
.stream()
.reduce("",
(accumulatedStr, str) -> accumulatedStr + str); //accumulator
Run Code Online (Sandbox Code Playgroud)
这有助于您可视化正在发生的事情:
累加器功能将您(红色)流中的元素逐步转换为最终的缩减(绿色)值.累加器函数只是将String
对象转换为另一个对象String
.
假设具有相同的4个字符串:您的新目标是总计它们的长度,并且您希望并行化您的流.
你需要的是这样的:
int length = Arrays.asList("one", "two","three","four")
.parallelStream()
.reduce(0,
(accumulatedInt, str) -> accumulatedInt + str.length(), //accumulator
(accumulatedInt, accumulatedInt2) -> accumulatedInt + accumulatedInt2); //combiner
Run Code Online (Sandbox Code Playgroud)
这是一个正在发生的事情的计划
累加器函数(a BiFunction
)允许您将String
数据转换为int
数据.作为流并行,它被分成两个(红色)部分,每个部分彼此独立地精心制作并产生尽可能多的部分(橙色)结果.需要定义组合器以提供将部分int
结果合并到最终(绿色)结果的规则int
.
如果您不想并行化您的流,该怎么办?好吧,无论如何都需要提供一个组合器,但是不会被调用,因为不会产生部分结果.
Era*_*ran 65
reduce
您尝试使用的两个和三个参数版本不接受相同的类型accumulator
.
两个参数reduce
被定义为:
T reduce(T identity,
BinaryOperator<T> accumulator)
Run Code Online (Sandbox Code Playgroud)
在你的情况下,T是String,所以BinaryOperator<T>
应该接受两个String参数并返回一个String.但是你传递给它一个int和一个String,这会导致你得到的编译错误 - argument mismatch; int cannot be converted to java.lang.String
.实际上,我认为传递0作为身份值在这里也是错误的,因为期望String(T).
另请注意,此版本的reduce处理Ts流并返回T,因此您无法使用它将String流减少为int.
这三个参数reduce
被定义为:
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
Run Code Online (Sandbox Code Playgroud)
在你的情况下,U是Integer,T是String,所以这个方法会将String流减少为Integer.
对于BiFunction<U,? super T,U>
累加器,您可以传递两种不同类型的参数(U和?super T),在您的情况下是Integer和String.另外,标识值U在你的情况下接受一个Integer,所以传递0就可以了.
实现您想要的另一种方式:
int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
.reduce(0, (accumulatedInt, len) -> accumulatedInt + len);
Run Code Online (Sandbox Code Playgroud)
这里流的类型与返回类型匹配reduce
,因此您可以使用两个参数版本reduce
.
当然你根本不需要使用reduce
:
int length = asList("str1", "str2").stream().mapToInt (s -> s.length())
.sum();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
32244 次 |
最近记录: |