21 java reduce java-8 java-stream
我试图了解该reduce()方法如何在java-8中工作。
例如,我有以下代码:
public class App {
public static void main(String[] args) {
String[] arr = {"lorem", "ipsum", "sit", "amet"};
List<String> strs = Arrays.asList(arr);
int ijk = strs.stream().reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a * b;
});
System.out.println(ijk);
}
}
Run Code Online (Sandbox Code Playgroud)
输出是这样的:
Accumulator, a = 0, b = lorem
Accumulator, a = 5, b = ipsum
Accumulator, a = 10, b = sit
Accumulator, a = 13, b = amet
17
Run Code Online (Sandbox Code Playgroud)
它是这些字符串长度的总和。而且我看到没有访问组合器,因此它不会与数字相乘,只会将数字相加。
但是,如果我有这些信息流:
int ijk = strs.parallelStream().reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a * b;
});
System.out.println(ijk);
Run Code Online (Sandbox Code Playgroud)
这是输出:
Accumulator, a = 0, b = ipsum
Accumulator, a = 0, b = lorem
Accumulator, a = 0, b = sit
Combiner
Accumulator, a = 0, b = amet
Combiner
Combiner
300
Run Code Online (Sandbox Code Playgroud)
我看到累加器和合并器都被访问了,但是只有乘法才返回。那么总和会怎样?
Eug*_*ene 18
您应该阅读说明文档reduce:
此外,组合器功能必须与累加器功能兼容;对于所有u和t,必须满足以下条件:
Combiner.apply(u,accumulator.apply(identity,t))==累加器.apply(u,t)
在你的情况,你打破了法律(做一个总和在accumulator和乘法的combiner),所以你对这样的操作看,真是不定,依赖于Spliterator的底层源代码是如何实现的结果(不这样做!)。
此外,combiner在只要求并行流。
当然,您的整个方法可以简化为:
Arrays.asList("lorem", "ipsum", "sit", "amet")
.stream()
.mapToInt(String::length)
.sum();
Run Code Online (Sandbox Code Playgroud)
如果您仅出于学习目的而这样做,则正确的reduce方法是(获取sum):
strs.parallelStream()
.reduce(0,
(a, b) -> {
System.out.println("Accumulator, a = " + a + ", b = " + b);
return a + b.length();
},
(a, b) -> {
System.out.println("Combiner");
return a + b;
});
Run Code Online (Sandbox Code Playgroud)
Dea*_*ool 12
关键概念:身份,累加器和组合器
Stream.reduce()操作:让我们将操作的参与者元素分解为单独的块。这样,我们将更容易理解每个人扮演的角色
当流并行执行时,Java运行时会将流拆分为多个子流。在这种情况下,我们需要使用一种函数将子流的结果合并为一个。这就是组合器的作用
情况1:parallelStream如您的示例所示,Combiner与
情况2:示例累加器具有不同类型的参数
在这种情况下,我们有一个User对象流,累加器参数的类型为Integer和User。但是,累加器实现是整数的总和,因此编译器无法推断用户参数的类型。
List<User> users = Arrays.asList(new User("John", 30), new User("Julie", 35));
int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge());
Run Code Online (Sandbox Code Playgroud)
编译错误
The method reduce(User, BinaryOperator<User>) in the type Stream<User> is not applicable for the arguments (int, (<no type> partialAgeResult, <no type> user) -> {})
Run Code Online (Sandbox Code Playgroud)
我们可以通过使用Combiner来解决此问题:它是方法参考Integer::sum或使用lambda表达式(a,b)->a+b
int computedAges = users.stream().reduce(0, (partialAgeResult, user) -> partialAgeResult + user.getAge(),Integer::sum);
Run Code Online (Sandbox Code Playgroud)
简而言之,如果我们使用顺序流并且累加器参数的类型和其实现的类型匹配,则无需使用组合器。
有3种减少使用java-stream的方法。简而言之,Stream::reduce从两个后续项(或与第一项相同的标识值)开始,并执行一项操作以产生新的折减值。对于每个下一项,都会发生同样的情况,并以减小的值执行操作。
比方说,你有流'a','b','c'和'd'。约简执行以下操作序列:
result = operationOn('a', 'b')- operationOn可能是任何东西(输入长度的总和。)result = operationOn(result, 'c')result = operationOn(result, 'd')result is returned方法是:
Optional<T> reduce(BinaryOperator<T> accumulator)对元素进行归约。从头两个项目产生一个减少的值开始,然后每个项目都有一个减少的值。该Optional<T>返回,因为它不能保证输入流不为空。
T reduce(T identity, BinaryOperator<T> accumulator)与上面的方法相同,只是将身份值作为第一项给出。T之所以返回,是因为总是保证至少有一项T identity。
U reduce(U identity, BiFunction<U,? super T, U> accumulator, BinaryOperator<U> combiner)与上述方法相同,不同之处在于将功能组合在一起。U之所以返回,是因为总是保证至少有一项U identity。
我假设您选择进行加法和乘法作为演示,看看到底会发生什么。
正如您已经注意到的,并且正如已经提到的,组合器仅在并行流上被调用。
简而言之,在并行流上,流的一部分(分别是底层的 Spliterator)被切断并由不同的线程处理。处理多个部分后,它们的结果将通过组合器组合。
在您的情况下,这四个元素都由不同的线程处理,然后按元素进行组合。这就是为什么您看不到任何加法(除了0 +)被应用,而只有乘法。
然而,为了获得有意义的结果,您应该从 切换*到+并执行更有意义的输出。
| 归档时间: |
|
| 查看次数: |
1739 次 |
| 最近记录: |