为什么 Optional 或 flatMap 方法的供应商类型参数是通配符?

2022-09-01 11:41:55

Optional.or 方法是在 Java 9 中添加的。这是方法签名

public Optional<T> or​(Supplier<? extends Optional<? extends T>> supplier)

为什么 take 的类型参数不仅仅是 ,因为它是最终类?Supplier? extends OptionalOptionalOptional

对于该方法也是如此。这是与 Java 8 相比的更改。Optional.flatMap

在Java 8中,它被更改为Java 9。Function<? super T, Optional<U>> mapperFunction<? super T,​? extends Optional<? extends U>>


答案 1

我从斯图尔特·马克斯本人那里找到了这背后的原因。

http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html

这与嵌套泛型有关( 嵌套在 )。从邮件线程OptionalFunction

 Function<..., Optional<StringBuilder>>

不是 的子类型

 Function<..., Optional<? extends CharSequence>>

为了解决这个问题,我们还必须添加外部通配符,以便

 Function<..., Optional<StringBuilder>>

是 的子类型

 Function<..., ? extends Optional<? extends CharSequence>>

答案 2

FWIW,在Java 11中的Stream.iterateStream.iterate中仍然存在类似的协变参数问题。当前方法签名为

static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)

这些签名不允许种子和 s 的某些组合,从类型的角度来看是合理的,例如,以下内容不会编译:UnaryOperator

UnaryOperator<String> op = s -> s; 
Stream<CharSequence> scs = iterate("", op); // error

建议的解决方案是将方法签名更改为

static <T, S extends T> Stream<T> iterate(S seed, Predicate<? super S> hasNext, UnaryOperator<S> next)
static <T, S extends T> Stream<T> iterate(S seed, UnaryOperator<S> f)

因此,与Anport.orAntimant.flatMap相比,这是“附加类型参数方法”实际起作用的情况。


推荐