我有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
有了上述内容,输出可能是“蝙蝠猫吃”还是“吃蝙蝠猫”?是否在规范的某处保证了?
答案 0 :(得分:6)
我之前的回答不正确(感谢@shmosel纠正我)。
现在我说,根据规范,它尊重元素的顺序。
证明非常简单。 specification声称缩减功能必须 关联。
然而, 关联性 如果不保留订单,那么它自身没有任何意义。根据关联属性的mathematical definition:
在一行中包含两次或多次出现的表达式中 相同的关联运算符,即运算的顺序 只要操作数的顺序是,执行与无关 未更改。
换句话说,关联属性并不意味着:
(a + b) + c = (a + c) + b
它只允许对应用操作的顺序进行任意排列。
答案 1 :(得分:2)
当您使用Stream.of()时,文档说:
返回顺序有序流,其元素是指定值。
所以在这一点上,你知道你有一个有序的顺序流,stream ops的javadoc也说:
对于顺序流,遇到顺序的存在与否不会影响性能,只影响确定性。 如果订购了流,则在相同来源上重复执行相同的流管道将产生相同的结果;如果没有订购,重复执行可能会产生不同的结果。
仅针对reduce
操作,当顺序流的顺序存在时,结果应该相同,即使对于并行有序流,操作也将保持最终顺序(至少在当前实现中对于java8和java9,将来可能会发生一些优化,但使用reduce
的有序流的顺序可能永远不会改变)。
您必须小心了解订购流的时间。例如,map
或filter
等操作会保留流的顺序,因此如果您有一个有序流,则可以使用此方法并继续对流进行排序。
注意:有序与排序完全不同。
如果订购了流,则大多数操作都被约束为对其遭遇顺序中的元素进行操作;如果流的源是包含[1,2,3]的List,那么执行map(x - > x * 2)的结果必须是[2,4,6]
编辑(根据评论):
但不限于按顺序执行。
这就是为什么关联性是必要的,例如,如果你有一个像这样的数组生成的流{a
,b
,c
,d
} ,然后可以先解析a
+ b
,然后c
+ d
,最后解决所有问题(a
+ b
)+({ {1}} + c
),这就是为什么操作必须是关联的。这样,如果操作确实是关联的(就像它必须的那样),那么最终的顺序将被保留。
答案 2 :(得分:2)
您已经在一个问题中提出了两个问题。
- java是否对有序的顺序流(例如列表中的默认流)强制执行,根据遭遇顺序总是会减少?
醇>
假设“将永远发生”指的是功能评估的顺序,答案是否,这是不可保证的。
- 醇>
有了上述,输出可能是“蝙蝠猫吃”或“吃蝙蝠猫”?是否在规范的某处保证了?Stream.of(" cats ", " eat ", " bats ") .reduce("", (a, b) -> a + b); // cats eat bats
无论缩减功能的评估顺序(处理顺序)如何,结果都保证为" 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"