在 Stream.reduce() 这样的 API 中选择不变性的好理由是什么?
回顾 Java 8 API 设计,我对 Stream.reduce()
参数上的通用不变性感到惊讶:Stream
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
同一 API 的看似更通用的版本可能已对 的单个引用应用了协方差/逆变,例如:U
<U> U reduce(U identity,
BiFunction<? super U, ? super T, ? extends U> accumulator,
BiFunction<? super U, ? super U, ? extends U> combiner)
这将允许以下情况,目前这是不可能的:
// Assuming we want to reuse these tools all over the place:
BiFunction<Number, Number, Double> numberAdder =
(t, u) -> t.doubleValue() + u.doubleValue();
// This currently doesn't work, but would work with the suggestion
Stream<Number> stream = Stream.of(1, 2L, 3.0);
double sum = stream.reduce(0.0, numberAdder, numberAdder);
解决方法是使用方法引用将类型“强制”为目标类型:
double sum = stream.reduce(0.0, numberAdder::apply, numberAdder::apply);
C#没有这个特殊的问题,因为Func(T1,T2,TResult)
定义如下,使用声明站点方差,这意味着任何使用API的API都免费获得此行为:Func
public delegate TResult Func<in T1, in T2, out TResult>(
T1 arg1,
T2 arg2
)
与建议的设计相比,现有设计的优势(以及EG决策的原因)是什么?
或者,换个角度问,我建议的设计中有哪些警告,我可能会忽略(例如,类型推断困难,并行化约束,或特定于约简操作的约束,例如关联性,对未来Java的声明站点差异的预期,...)?BiFunction<in T, in U, out R>