首页 > 解决方案 > Java流如何减少累加器参数是关联的

问题描述

问题是关于

java.util.stream.Stream.reduce(U identity,
             BiFunction<U, ? super T, U> accumulator,
             BinaryOperator<U> combiner) 

方法。

从 API 文档:

累加器——一种关联的、非干扰的、无状态的函数,用于将附加元素合并到结果中

现在,联想的定义是:

(a op b) op c = a op (b op c) for all a, b, c

正如我们所看到的,上面的定义需要一个 BinaryOperator,而不仅仅是一个 BiFunction,因为a op brequires bof typeTb op crequires bof type U。如果UT是不同的,这是不可能的。


我的问题

如何为不是 BinaryOperator 的 BiFunction 制定关联的定义?


更新

我已向 Oracle 提交了关于此问题的错误,内部审核 ID:9063337

我将根据 Oracle 的反馈更新问题。

标签: javajava-8java-stream

解决方案


注意文档

此外,combiner功能必须与accumulator功能兼容;对于所有ut,必须满足以下条件:

combiner.apply(u, accumulator.apply(identity, t)) == accumulator.apply(u, t)

==不是字面意思,而是“等价的结果”</sup>

所以事实上,我们对关联性的约束要强得多accumulator,因为它必须与 兼容combiner,后者是一个关联函数。

还有 API 注意:

许多使用这种形式的归约可以通过 map 和 reduce 操作的显式组合更简单地表示。accumulator 函数充当融合的映射器和累加器,有时比单独的映射和归约更有效,...</p>

accumulator函数是融合映射和归约函数时,只有归约部分必须是关联的。当您要测试该部分时,只需测试该combiner函数是否满足关联性约束以及是否combineraccumulator指定方式兼容。如果两者都被证明,则accumulator' 的归约部分的结合性也被证明了。

虽然 API Note 说“使用这种形式进行了许多归约”,但实际上所有这些都可以表示为 map 和 reduce 操作的显式组合,当我们忽略效率时,由于指定的约束:

Function<T,U> mappingFunc = t -> accumulator.apply(identitiy, t);
U result = streamOfT.map(mappingFunc).reduce(identitiy, combiner);

result必须等同于,例如,一个典型的顺序评估的结果streamOfT.reduce(identitiy, accumulator, combiner),它根本不使用combiner

我们可以为关联性制定狭窄的测试用例为

U u1 = accumulator.apply(accumulator.apply(identitiy, t1), t2);
U u2 = combiner.apply(accumulator.apply(identitiy, t1), accumulator.apply(identitiy, t2));

其中u1u2必须是等价的结果,以及

U u1 = accumulator.apply(accumulator.apply(accumulator.apply(identitiy, t1), t2), t3);
U u2 = combiner.apply(accumulator.apply(identitiy, t1),
           accumulator.apply(accumulator.apply(identitiy, t2), t3));

推荐阅读