Java 有序流上的减少是否按顺序减少?

Java 有序流上的减少是否按顺序减少?,java,java-8,java-stream,Java,Java 8,Java Stream,我有一个a、B、C的列表 C减少A减少B!=A reduce B reduce C(但是,A reduce(B reduce C)可以) 换句话说,我的约化运算是关联的,但不是交换的 java是否在有序的顺序流(例如列表中的默认流)上强制执行减少总是根据遭遇顺序进行的?也就是说,java是否会重新排序缩减(使B减少A而不是A减少B) (希望这足够清楚) 编辑以添加一个小演示,可能有助于澄清 Stream.of(" cats ", " eat ", " bats ") .reduce("",

我有一个a、B、C的
列表

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

换句话说,我的约化运算是关联的,但不是交换的

java是否在有序的顺序流(例如列表中的默认流)上强制执行减少总是根据遭遇顺序进行的?也就是说,java是否会重新排序缩减(使B减少A而不是A减少B)

(希望这足够清楚)

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

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

有了以上这些,输出会是“蝙蝠猫吃”还是“吃蝙蝠猫”?这在规范中有保证吗?

根据规范,它尊重元素的顺序

证明很简单。要求缩减函数必须是关联的

但是,如果不保留顺序,关联性本身就没有任何意义。根据关联属性的定义:

在包含一行中两个或多个引用的表达式中 相同的关联运算符,即操作的顺序 只要操作数序列是
未更改

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

(a + b) + c = (a + c) + b
它只允许对应用操作的顺序进行任意排列。

当您使用文档时,会显示:

返回其元素为指定值的有序流

在这一点上,您知道您有一个有序的顺序流,并且

对于连续流,相遇顺序的存在或不存在并不影响性能,只影响确定性如果对流进行排序,则在相同源上重复执行相同的流管道将产生相同的结果;如果不进行排序,重复执行可能会产生不同的结果

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

您必须仔细了解流的排序时间。例如,像
map
filter
这样的操作会保留流的顺序,因此如果您有一个已排序的流,您可以使用此方法,流将继续排序

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

如果一个流是有序的,那么大多数操作都会被约束为按遭遇顺序对元素进行操作;如果一个流的源是一个包含[1,2,3]的列表,那么执行map(x->x*2)的结果必须是[2,4,6]

编辑(根据评论):

但不限于按顺序执行

这就是为什么关联性是必要的,例如,如果您有一个从这样的数组生成的流{
a
b
c
d
,那么
a
+
b
可以首先解析,然后
c
+
d
,最后一起解析(
a
+
b
)(
c
+
d
),这就是为什么操作必须是关联的。这样,如果操作确实是关联的(必须是关联的),那么最终的顺序将被保留


我所关心的是reduce文档中的这条简介“这相当于……但不限于按顺序执行。”


允许流管道执行
“cats”+(“eat”+“bats”)
(“cats”+“eat”)+“bats”

您在一个问题中问了两个问题

  • java是否在有序的顺序流(例如列表中的默认流)上强制执行减少总是根据遭遇顺序进行的
  • 假设“总是会发生”是指函数求值的顺序,答案是否定的,这是不能保证的

  • 有了以上内容,输出会是“蝙蝠猫吃”还是“蝙蝠猫吃”?这在规范中有保证吗
  • 无论归约函数的求值顺序(处理顺序)如何,结果都保证是“猫吃蝙蝠”
    ,正确反映遭遇顺序(另请参见).为确保未指定的处理顺序仍然产生关于遭遇顺序的正确结果,缩减函数必须是关联的

    请注意,甚至将
    .reduce(“,String::concat)
    作为有效但低效的缩减函数的示例。类似地,
    (a,b)->b
    作为获取流的最后一个元素的有效方法

    关键点见下表:

    结合性 如果以下条件成立,则运算符或函数
    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)
    
    因此,我们可以与
    (c op d)
    并行计算
    (a op b)
    ,然后对结果调用
    op

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


    @Andremoniy@shmosel好的,但这是列表的缩减,而不是特定的列表元素的缩减!!@Andremoniy我想它的意思是
    op.apply(op.apply(a,b),c)
    ,其中
    op
    二进制运算符
    @DD你已经设法让事情变得更加混乱了。@shmosel
    reduce(“,(a,b)->a++b)
    将违反有关身份价值的合同,
    a op b op c op d == (a op b) op (c op d)