有序流上的减少是按顺序减少的吗?

时间:2018-03-27 18:39:54

标签: java java-8 java-stream

我有A,B,C的List

C reduce A reduce B != A reduce B reduce C(但是,减少(B减少C)是可以的)。

换句话说,我的缩减操作是关联的,但不是可交换的。

java是否对有序顺序流(例如列表中的默认流)执行减少将始终根据遭遇顺序进行减少?也就是说,java会重新排序减少(这样B减少A而不是A减少B)?

(希望这很清楚)。

编辑添加一个小演示,可能有助于澄清

Stream.of(" cats ", " eat ", " bats ")
  .reduce("", (a, b) -> a + b); // cats eat bats

有了上述内容,输出可能是“蝙蝠猫吃”​​还是“吃蝙蝠猫”?是否在规范的某处保证了?

4 个答案:

答案 0 :(得分:6)

我之前的回答不正确(感谢@shmosel纠正我)。

现在我说,根据规范,它尊重元素的顺序。

证明非常简单。 specification声称缩减功能必须 关联

然而, 关联性 如果不保留订单,那么它自身没有任何意义。根据关联属性的mathematical definition

  

在一行中包含两次或多次出现的表达式中   相同的关联运算符,即运算的顺序   只要操作数的顺序是,执行与无关   未更改

换句话说,关联属性并不意味着:

(a + b) + c = (a + c) + b

它只允许对应用操作的顺序进行任意排列。

答案 1 :(得分:2)

当您使用Stream.of()时,文档说:

  

返回顺序有序流,其元素是指定值。

所以在这一点上,你知道你有一个有序的顺序流,stream ops的javadoc也说:

  

对于顺序流,遇到顺序的存在与否不会影响性能,只影响确定性。 如果订购了流,则在相同来源上重复执行相同的流管道将产生相同的结果;如果没有订购,重复执行可能会产生不同的结果。

仅针对reduce操作,当顺序流的顺序存在时,结果应该相同,即使对于并行有序流,操作也将保持最终顺序(至少在当前实现中对于java8和java9,将来可能会发生一些优化,但使用reduce的有序流的顺序可能永远不会改变)。

您必须小心了解订购流的时间。例如,mapfilter等操作会保留流的顺序,因此如果您有一个有序流,则可以使用此方法并继续对流进行排序。

注意:有序与排序完全不同

  

如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作;如果流的源是包含[1,2,3]的List,那么执行map(x - > x * 2)的结果必须是[2,4,6]

编辑(根据评论):

  

但不限于按顺序执行。

这就是为什么关联性是必要的,例如,如果你有一个像这样的数组生成的流{abcd} ,然后可以先解析a + b,然后c + d,最后解决所有问题(a + b)+({ {1}} + c),这就是为什么操作必须是关联的。这样,如果操作确实是关联的(就像它必须的那样),那么最终的顺序将被保留。

答案 2 :(得分:2)

您已经在一个问题中提出了两个问题。

  
      
  1. java是否对有序的顺序流(例如列表中的默认流)强制执行,根据遭遇顺序总是会减少?
  2.   

假设“将永远发生”指的是功能评估的顺序,答案是,这是不可保证的。

  
      
  1. Stream.of(" cats ", " eat ", " bats ")
      .reduce("", (a, b) -> a + b); // cats eat bats
    
         有了上述,输出可能是“蝙蝠猫吃”​​或“吃蝙蝠猫”?是否在规范的某处保证了?
  2.   

无论缩减功能的评估顺序(处理顺序)如何,结果都保证为" cats eat bats ",正确反映遭遇顺序(另见this answer)。为了确保未指定的处理顺序仍然产生关于遭遇顺序的正确结果,还原函数必须关联as specified

请注意,the documentation甚至会将.reduce("", String::concat)显示为有效但效率低下的缩减功能的示例。同样,(a,b) -> b has been acknowledged是获取流的最后一个元素的有效方法。

关键点在“Associativity” section of the documentation

中给出
  

结合性

     

如果符合以下条件,则运算符或函数op关联

(a op b) op c == a op (b op c)
     

如果我们将其扩展到四个术语,可以看出这对并行评估的重要性:

a op b op c op d == (a op b) op (c op d)
     

因此,我们可以与(a op b)并行评估(c op d),然后对结果调用op

     

关联操作的示例包括数字加法,最小值和最大值以及字符串连接。

答案 3 :(得分:0)

  

我担心的是减少文档中的这种模糊"这相当于...但不限于按顺序执行。"

Execution order is not the same as encounter order.流管道可以执行"cats" + ("eat" + "bats")("cats" + "eat") + "bats"