Why does adding “.map(a -> a)” allow this to compile?

我与影子孤独终老i 提交于 2019-11-28 19:17:38

Unless I am missing something in how FunctionalInterface inferences occur, it seems pretty obvious that you can't call reduce on a Stream < ? super Predicate > because it does not have sufficient typing to be inferred as a BinaryOperator.

The method reference hides a very important part of the story, the second parameter.

return predicates.map(a->a).reduce((predicate, other) -> predicate.or(other));

If you remove the call to map, the compiler does not have the opportunity to type the stream appropriately to satisfy the second capture requirements. With map the compiler is given the latitude to determine the types required to satisfy the captures, but without a concrete binding of the generics the two captures can only be satisfied with a Stream of Object which is likely what would result through map().

The Predicate interface as implemented now is simply building a chain, but the use is expected to be a composed entity. It is assumed to take a single parameter, but in fact the nature of AND and OR require two parameters without a type guarantee because of the shortcomings of Java's generics. In this way the API seems to be less than ideally designed.

The call to map() cedes the control of the typing, from the explicit Stream of Predicates, to one the compiler can guarantee will satisfy all captures.

The following both satisfy the compiler in IDEone, by directly inducing a flexible enough type in the case of Object, or a known type in the case of T.

public <T> Optional<? extends Predicate<? super T>> with(Stream<Predicate<Object>> predicates)
public <T> Optional<? extends Predicate<? super T>> with(Stream<Predicate<T>> predicates)

Java generics still need a way to force capture type equivalence, as the helper methods are clearly not enough.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!