[英]Using parallel stream in Java but not getting the expected value
我有一个关于字数统计的代码段:
String[] wordCountArr = {"a", "b", "c", "a", "a", "b", "c", "d", "e"};
Stream.of(wordCountArr).collect(TreeMap::new,
(treeMap, str) -> {
Object countValue = treeMap.get(str);
if (countValue != null) {
Integer count = Integer.valueOf(countValue.toString());
treeMap.put(str, count + 1);
}
else {
treeMap.put(str, 1);
}
}, (treeMap, treeMap2) -> {
treeMap.putAll(treeMap2);
}).entrySet()
.forEach(System.out::println);
它得到期望值:a = 3 b = 2 c = 2 d = 1 e = 1,但是collect函数的Combiner似乎没有执行。 然后我得到了: Java 8 Stream-Reduce函数的组合器未执行 ,并将代码更改为:
Stream.of(wordCountArr).parallel().collect(TreeMap::new,
(treeMap, str) -> {
Object countValue = treeMap.get(str);
if (countValue != null) {
Integer count = Integer.valueOf(countValue.toString());
treeMap.put(str, count + 1);
}
else {
treeMap.put(str, 1);
}
}, (treeMap, treeMap2) -> {
treeMap.putAll(treeMap2);
}).entrySet()
.forEach(System.out::println);
但结果并非预期:a = 1 b = 1 c = 1 d = 1 e = 1,我想也许putAll函数只是替换了旧的映射。 有什么好主意可以得出正确的结果吗? 使用并行流是否更有效? 谢谢!
解决了:
仅当使用并行流时框架尝试加入多个fork的结果时,才执行组合器。
因此,在第一个版本中,合并器不会执行。
您的第二个版本的代码可能会导致ConcurrentModificationException,因为使用并行流时TreeMap不是线程安全的。
还有一点是,当您合并两棵树时,您忘记了对两棵树的值求和。 您将treeMap
所有内容与treeMap
合并,因此treeMap2
的当前值treeMap
被丢弃: treeMap.putAll(treeMap2);
您必须手动遍历treeMap
键,将值与treeMap2
相加, treeMap2
。
我不知道您为什么要使用这种方法,但是要计算每个组的项目,您可以简单地使用groupingBy
:
Map<String, Long> countMap = Stream.of(wordCountArr).collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
String[] wordCountArr = {"a", "b", "c", "a", "a", "b", "c", "d", "e"};
Map<String, Long> countMap = Stream.of(wordCountArr).collect(Collectors.groupingBy(letter -> letter, Collectors.counting()));
countMap.forEach((s, count) -> System.out.println(s + " : " + count));
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.