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

时间:2018-12-10 01:25:12

标签: java optional java-9 supplier

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

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

由于Supplier final 类,为什么? extends Optional的类型参数采用Optional而不是Optional

Optional.flatMap方法也是如此。这是对Java 8的更改。

在Java 8中,它是Function<? super T, Optional<U>> mapper,而在Java 9中已更改为Function<? super T,​? extends Optional<? extends U>>

3 个答案:

答案 0 :(得分:35)

我从Stuart Marks自己那里找到了背后的原因

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

这与嵌套泛型有关(Optional嵌套在Function中)。 在邮件线程中

 Function<..., Optional<StringBuilder>>
     

不是的子类型

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

要解决此问题,我们还必须添加外部通配符,以便

 Function<..., Optional<StringBuilder>>
     

的子类型
 Function<..., ? extends Optional<? extends CharSequence>>

答案 1 :(得分:10)

FWIW,Java 11中的issueStream.iterate中仍然存在类似的带有协变参数的Stream.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)

这些签名不允许种子和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)

因此,与Optional.orOptional.flatMap相比,这是“附加类型参数方法”实际上有效的情况。

答案 2 :(得分:9)

是的...据说通配符带有扩展绑定(上限)会使类型成为协变,这意味着例如List<Apple>是{{ 1}}(考虑到List<? extends Fruit>扩展了Apple);这也称为协方差

或者在您显示的示例中,这意味着FruitOptional<StringBuilder>的子类型,因此您可以执行以下操作:

Optional<? extends Optional<? extends CharSequence>>

或将List<Optional<String>> left = new ArrayList<>(); List<? extends Optional<? extends CharSequence>> right = new ArrayList<>(); right = left; // will compile 分配给另一个