Reputation: 17910
The Optional.or
method was added in Java 9. This is the method signature
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Why is the type parameter of the Supplier
taking ? extends Optional
rather than just Optional
, since Optional
is a final class?
The same is true for the Optional.flatMap
method. This is a change from Java 8.
In Java 8, it was Function<? super T, Optional<U>> mapper
whereas it was changed to Function<? super T,? extends Optional<? extends U>>
in Java 9.
Upvotes: 30
Views: 1591
Reputation: 120988
Yeah... it is said that wildcard with an extends-bound (upper bound) makes the type covariant, which means that for example List<Apple>
is an actual subtype of List<? extends Fruit>
(considering that Apple
extends Fruit
); this is also called covariance.
Or in the examples that you have shown, it means that Optional<StringBuilder>
is a subtype of Optional<? extends Optional<? extends CharSequence>>
, so you could for example do:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
or assign a Function
to the other
Upvotes: 9
Reputation: 3212
FWIW, a similar issue with covariant arguments still exists in Stream.iterate and Stream.iterate in Java 11. The current method signatures are
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
These signatures do not allow for some combinations of seeds and UnaryOperator
s that are sound from a type perspective, e.g. the following doesn't compile:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
The proposed solution is to change the method signatures to
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)
So, in contrast to Optional.or and Optional.flatMap this is a case where the "additional-type-parameter approach" actually works.
Upvotes: 11
Reputation: 17910
I found the reasoning behind this from Stuart Marks himself
http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-October/044026.html
This has to do with nested generics (Optional
is nested within Function
).
From the mail thread
Function<..., Optional<StringBuilder>>
is not a subtype of
Function<..., Optional<? extends CharSequence>>
To get around this, we have to add the outer wildcard as well, so that
Function<..., Optional<StringBuilder>>
is a subtype of
Function<..., ? extends Optional<? extends CharSequence>>
Upvotes: 37