java - 流收集累加器/组合器订单
问题描述
这基本上是我的这个答案的后续行动。
假设我正在开发自定义收集器,并假设accumulator
总是会向供应商返回的集合添加一些元素,是否有可能在combiner
调用时,中间结果之一为空?一个例子可能更容易理解。
假设我有一个List
数字,我想将它拆分为列表列表,2
分隔符在哪里。所以比如说我有1, 2, 3, 4, 2, 8
,结果应该是[[1], [3, 4], [8]]
。这个实现起来其实并不复杂(不要过多评判代码,我写的很快,就是为了能写出这个问题)。
List<List<Integer>> result = Stream.of(1, 2, 3, 4, 2, 8)
.collect(Collector.of(
() -> new ArrayList<>(),
(list, elem) -> {
if (list.isEmpty()) {
List<Integer> inner = new ArrayList<>();
inner.add(elem);
list.add(inner);
} else {
if (elem == 2) {
list.add(new ArrayList<>());
} else {
List<Integer> last = list.get(list.size() - 1);
last.add(elem);
}
}
},
(left, right) -> {
// This is the real question here:
// can left or right be empty here?
return left;
}));
这在这个例子中可能无关紧要,但问题是:元素中的那个combiner
可以是空的List
吗?我真的很想说NO
,因为在文档中这些被称为:
combiner - 一个关联的、非干扰的、无状态的函数,它接受两个部分结果容器并将它们合并。
好吧,在他们到达之前,对我的偏爱是一个迹象,但只是想确定一下。accumulator
combiner
解决方案
不保证在合并之前累加器已应用于容器。换句话说,要合并的列表可能是空的。
为了证明这一点:
IntStream.range(0, 10).parallel().boxed()
.filter(i -> i >= 3 && i < 7)
.collect(ArrayList::new, List::add, (l1,l2)->{
System.out.println(l1.size()+" + "+l2.size());
l1.addAll(l2);
});
在我的机器上,它打印:
0 + 0
0 + 0
0 + 0
1 + 1
0 + 2
0 + 2
1 + 1
2 + 0
2 + 2
当筛选操作的结果尚不清楚时,工作负载拆分发生在源列表中。每个块都以相同的方式处理,无需重新检查是否有任何元素已到达累加器。
请注意,从 Java 9 开始,您还可以执行类似的操作
IntStream.range(0, 10).parallel().boxed()
.collect(Collectors.filtering(i -> i >= 3 && i < 7, Collectors.toList()));
toList()
这是收集器(这里是收集器)应该准备好遇到空容器的另一个原因,因为过滤发生在Stream
实现之外,并且accept
对复合收集器的累加器的调用并不总是意味着accept
对下游收集器的累加器的调用。
Collector
文档中指定了能够处理空容器的要求:
为了确保顺序和并行执行产生相同的结果,收集器函数必须满足一个身份和一个关联性约束。
恒等约束表示,对于任何部分累积的结果,将其与空结果容器组合必须产生等效结果。也就是说,对于作为
a
任何一系列累加器和组合器调用结果的部分累加结果,a
必须等价于combiner.apply(a, supplier.get())
.
推荐阅读
- python - discord python bot api调用输入错误?
- flutter - 使用 RiverPod 和 StateNotifiers 在加载时调用函数
- reactjs - 来自 Material UI React 的 FormControl
- c++ - 需要帮助理解 std::forward
- python - 支持 M2M 关联表中的重复条目
- angular - 为什么“mat-table”会报告“缺少页眉、页脚和行的定义;无法确定应该呈现哪些列”?
- c++ - 传递给函数时使用 std::vector 误解移动语义
- amazon-web-services - 多对多关系的Dynamodb单表结构
- stripe-payments - 如果用户没有足够的钱,则阻止试用版
- haskell - Haskell quickBatch: 应用类幺半群