Luk*_*der 20 java covariance contravariance java-stream invariance
回顾Java 8 Stream
API设计,我对Stream.reduce()
参数的泛型不变性感到惊讶:
<U> U reduce(U identity,
BiFunction<U,? super T,U> accumulator,
BinaryOperator<U> combiner)
Run Code Online (Sandbox Code Playgroud)
相同API的看似更通用的版本可能在个别引用上应用了协方差/逆变U
,例如:
<U> U reduce(U identity,
BiFunction<? super U, ? super T, ? extends U> accumulator,
BiFunction<? super U, ? super U, ? extends U> combiner)
Run Code Online (Sandbox Code Playgroud)
这将允许以下目前无法实现的目标:
// 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);
Run Code Online (Sandbox Code Playgroud)
解决方法,使用方法引用将类型"强制"为目标类型:
double sum = stream.reduce(0.0, numberAdder::apply, numberAdder::apply);
Run Code Online (Sandbox Code Playgroud)
C#没有Func(T1, T2, TResult)
使用声明 - 站点差异定义如下的特定问题,这意味着任何使用的API Func
都可以免费获得此行为:
public delegate TResult Func<in T1, in T2, out TResult>(
T1 arg1,
T2 arg2
)
Run Code Online (Sandbox Code Playgroud)
与现有设计相比,现有设计的优点(可能还有EG决策的原因)有哪些?
或者,换句话说,我可能会忽略的建议设计的注意事项(例如类型推断困难,并行化约束或特定于约简操作的约束,例如关联性,对未来Java声明站点方差的预期BiFunction<in T, in U, out R>
, ...)?
爬过lambda开发的历史并隔离这个决定的"原因"的原因很难 - 所以最终,人们将不得不等待其中一个开发人员回答这个问题.
一些提示可能如下:
流接口经历了多次迭代和重构.在Stream
界面的最早版本之一中,有一些专用reduce
方法,那些最接近reduce
问题中方法的方法仍然被称为Stream#fold
.这其中已经收到BinaryOperator
的combiner
参数.
有趣的是,很长一段时间,lambda提案包括一个专用接口Combiner<T,U,R>
.与直觉相反,这不是combiner
在Stream#reduce
函数中使用的.相反,它被用作reducer
,现在似乎是所谓的accumulator
.但是,Combiner
接口在以后的版本中被替换BiFunction
.
与此处问题最引人注目的相似之处在于有关Stream#flatMap
邮件列表中签名的帖子,然后将其转换为关于流方法签名的差异的一般问题.例如,他们在某些地方修复了这些问题
正如布莱恩纠正我:
<R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);
代替:
<R> Stream<R> flatMap(Function<T, Stream<? extends R>> mapper);
但注意到在某些地方,这是不可能的:
T reduce(T identity, BinaryOperator<T> accumulator);
和
Optional<T> reduce(BinaryOperator<T> accumulator);
无法修复,因为他们使用'BinaryOperator',但如果使用'BiFunction',那么我们有更多的灵活性
<U> U reduce(U identity, BiFunction<? super U, ? super T, ? extends U> accumulator, BinaryOperator<U> combiner)
代替:
<U> U reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner);
关于'BinaryOperator'的相同评论
(我强调).
我发现没有替换BinaryOperator
a 的唯一理由BiFunction
最终是在对此语句的响应中给出的,在同一个线程中:
BinaryOperator不会被BiFunction取代,即使如你所说,它引入了更多的灵活性,BinaryOperator要求两个参数和返回类型相同,因此它在概念上更加重要(EG已经投票了).
也许有人可以挖掘出专家组对这一决定的投票的特定参考,但也许这句话已经充分回答了为什么它是这样的问题......
归档时间: |
|
查看次数: |
454 次 |
最近记录: |