当前位置: 首页 > 知识库问答 >
问题:

收集合成器(供应商、累加器、合成器)的组合顺序在哪里定义?

强才捷
2023-03-14

JavaAPI文档声明集合方法的组合器参数必须是:

用于组合两个值的关联、非干扰、无状态函数,必须与累加器函数兼容

合路器是双余弦

例如,根据组合顺序,以下示例可能给出不同的结果:m1。添加所有(m2)或m2。addAll(m1)。

List<String> res = LongStream
     .rangeClosed(1, 1_000_000)
     .parallel()
     .mapToObj(n -> "" + n)
     .collect(ArrayList::new, ArrayList::add,(m1, m2) -> m1.addAll(m2));

我知道,在这种情况下,我们可以简单地使用方法句柄,例如ArrayList::addAll。然而,在某些情况下,需要Lambda,我们必须按正确的顺序组合项目,否则在并行处理时可能会得到不一致的结果。

这在Java 8 API文档的任何部分中都有声明吗?或者这真的无关紧要?

共有2个答案

赫连宏伯
2023-03-14

文件中似乎没有明确说明这一点。然而,streams API中有一个排序概念。流可以是有序的,也可以是非有序的。如果源拆分器是无序的(例如,如果流源是哈希集),则从一开始就可能是无序的。或者,如果用户显式使用了unordered()操作,则流可能会变得无序。如果流是有序的,那么收集过程也应该是稳定的,因此,我猜想,假设对于有序流,组合器以严格的顺序接收参数。然而,对于无序流,这并不能保证。

慕河
2023-03-14

当然,这很重要,当你使用m2时。添加所有(m1),而不是m1。addAll(m2),它不仅改变了元素的顺序,而且完全打破了操作。由于双消费者不返回结果,您无法控制调用方将使用哪个对象作为结果,并且由于调用方将使用第一个对象,因此修改第二个将导致数据丢失。

如果您查看类型为双余弦的累加器函数,就会得到一个提示

如果您查看收集器的文档,它使用二进制运算符作为合并器函数,因此允许合并器决定返回哪个参数(甚至是完全不同的结果实例),您会发现:

结合性约束表示,拆分计算必须产生等效结果。也就是说,对于任何输入元素t1和t2,以下计算中的结果r1和r2必须相等:

A a1 = supplier.get();
accumulator.accept(a1, t1);
accumulator.accept(a1, t2);
R r1 = finisher.apply(a1);  // result without splitting

A a2 = supplier.get();
accumulator.accept(a2, t1);
A a3 = supplier.get();
accumulator.accept(a3, t2);
R r2 = finisher.apply(combiner.apply(a2, a3));  // result with splitting

因此,如果我们假设累加器按相遇顺序应用,则组合器必须按从左到右的顺序组合第一个和第二个参数以产生等效的结果。

现在,三参数版本的Stream.collect有一个稍微不同的签名,使用Bi消费者作为组合器,正好支持像ArrayList::addAll这样的方法引用。假设所有这些操作都是一致的,并考虑到这个签名更改的目的,我们可以放心地假设它必须是要修改的容器的第一个参数。

但这似乎是一个较晚的更改,文档没有相应地进行调整。如果您查看包文档的可变归约部分,您会发现它已被修改以显示实际的流。收集的签名和用法示例,但重复与上面所示的关联性约束完全相同的定义,尽管事实上的finisher。如果组合器是双消费体,则应用(组合器。应用(a2,a3))不起作用…

留档问题已报告为JDK-8164691,并在Java

组合器-一个关联的、无干扰的、无状态的函数,它接受两个部分结果容器并将它们合并,这必须与累加器函数兼容。组合器函数必须将第二个结果容器中的元素折叠到第一个结果容器中。

 类似资料:
  • 问题内容: Java API文档指出该方法的参数必须为: 用于组合两个值的关联,无干扰,无状态函数,必须与累加器函数兼容 A 是一个a ,它接收两个type类型的参数并返回。但是文档没有说明我们是否应该将元素组合到第一个或第二个参数中? 例如,以下示例可能会根据组合be的顺序给出不同的结果: 或。 我知道在这种情况下,我们可以简单地使用方法句柄,例如。但是,在某些情况下,需要Lambda,并且必须

  • 问题内容: 我不了解以下方法的第三个参数的实用程序: 从javaDoc: 产生的结果等于: 如您所见,该参数未使用。例如,以下代码将字符串累积到ArrayList中: 但我期望这样: 问题答案: 在使用时,你的是平行的,因为在这种情况下,多个线程收集的元素到最终输出的子列表,并且这些子列表必须被组合以产生最终的。

  • 我不明白以下方法的第三个参数的效用: 来自Javadoc: 如您所见,没有使用参数。例如,以下内容将把字符串累加到ArrayList中: 但我预料到了这一点:

  • 我想使用聚合器从两条消息中创建一条消息,但我不知道如何做到这一点。 目前,我正在从一个目录中读取两个文件,并希望将这些消息聚合为一个。 我的整个项目是这样的: 读入。拉链- 如果我可以在解压缩文件后发送一条包含两个有效负载的消息,那就太好了,但在读取后聚合就足够了。 我的拉链看起来像这样: 它将这些文件放入两个目录中,我使用FileReadingMessageSource再次从中读取它们。我还想只

  • 目前,我正在与spring integration合作开发新的应用程序,并启动了poc,以了解如何处理故障案例。在我的应用程序中,spring integration将接收来自IBM mq的消息,并根据消息类型验证头信息和到不同队列的路由。传入的消息可能是批量消息,所以我使用了spring integration的拆分器和聚合器,并且对技术工作流程有很好的进展和控制。目前我面临的问题很少,我们有I

  • 示例程序: 所以,为了简化这里的问题,没有最终的转换,所以得到的代码非常简单。