Le Optional.or
la méthode a été ajoutée dans Java 9. C'est la signature de la méthode
public Optional<T> or(Supplier<? extends Optional<? extends T>> supplier)
Pourquoi le paramètre type de Supplier
prend-il ? extends Optional
plutôt que simplement Optional
, puisque Optional
est une classe finale ?
Il en va de même pour le Optional.flatMap
méthode. Ceci est un changement de Java 8.
Dans Java 8, c'était Function<? super T, Optional<U>> mapper
alors qu'il a été remplacé par Function<? super T,? extends Optional<? extends U>>
in Java 9.
J'ai trouvé le raisonnement derrière cela de Stuart Marks lui-même
http://mail.openjdk.Java.net/pipermail/core-libs-dev/2016-October/044026.html
Cela concerne les génériques imbriqués (Optional
est imbriqué dans Function
). À partir du fil de discussion
Function<..., Optional<StringBuilder>>
n'est pas un sous-type de
Function<..., Optional<? extends CharSequence>>
Pour contourner cela, nous devons également ajouter le caractère générique externe, afin que
Function<..., Optional<StringBuilder>>
est un sous-type de
Function<..., ? extends Optional<? extends CharSequence>>
FWIW, un problème similaire avec des arguments covariants existe toujours dans Stream.iterate et Stream.iterate dans Java 11. Les signatures de méthode actuelles sont
static <T> Stream<T> iterate(T seed, Predicate<? super T> hasNext, UnaryOperator<T> next)
static <T> Stream<T> iterate(T seed, UnaryOperator<T> f)
Ces signatures ne permettent pas certaines combinaisons de graines et de UnaryOperator
qui sont saines du point de vue du type, par exemple ce qui suit ne se compile pas:
UnaryOperator<String> op = s -> s;
Stream<CharSequence> scs = iterate("", op); // error
La solution proposée consiste à remplacer les signatures de méthode par
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)
Donc, contrairement à Optional.or et Optional.flatMap c'est un cas où "l'approche de type de paramètre supplémentaire" fonctionne réellement.
Ouais ... on dit que le caractère générique avec une extension-borne (borne supérieure) rend le type covariant, ce qui signifie que par exemple List<Apple>
est un sous-type réel de List<? extends Fruit>
(considérant que Apple
étend Fruit
); cela s'appelle aussi covariance.
Ou dans les exemples que vous avez montrés, cela signifie que Optional<StringBuilder>
est un sous-type de Optional<? extends Optional<? extends CharSequence>>
, vous pouvez par exemple faire:
List<Optional<String>> left = new ArrayList<>();
List<? extends Optional<? extends CharSequence>> right = new ArrayList<>();
right = left; // will compile
ou attribuez un Function
à l'autre