Optional<ArrayList<String>> option = Optional.of(new ArrayList<>());
Optional<ArrayList<?>> doesntWork = option;
Optional<ArrayList<?>> works = option.map(list -> list);
La première tentative d'affectation ne se compile pas, mais la seconde avec le map
le fait. Il semble que le map
ne devrait en fait rien accomplir, mais pour une raison quelconque, cela transforme mon Optional<ArrayList<String>>
dans un Optional<ArrayList<?>>
. Y a-t-il une sorte de distribution implicite en cours?
Si vous regardez dans le code de map
et suivez tous les appels de méthode, vous verrez que option.map(list -> list)
finit par retourner new Optional<>(option.get())
. Vous pouvez donc remplacer votre dernière mission par:
Optional<ArrayList<?>> works = new Optional<>(option.get());
Cela crée un nouveau Optional<ArrayList<?>>
Et initialise sa variable d'instance value
(dont le type est ArrayList<?>
) Avec le ArrayList<String>
Renvoyé par map.get()
. Ceci est une affectation valide.
Y a-t-il une sorte de distribution implicite en cours?
Non, map
renvoie une nouvelle instance Optional
. Il ne convertit pas l'instance d'origine sur laquelle il a été appelé.
Voici la chaîne d'appels de méthode:
option.map(list -> list)
renvoie (puisque option
n'est pas vide)
Optional.ofNullable(mapper.apply(value))
qui dans votre cas est le même que
Optional.ofNullable(value)
qui retourne (puisque la valeur n'est pas nulle):
Optional.of(value)
qui revient
new Optional<>(value)
Eh bien le premier ne fonctionne pas car les génériques sont invariants, la seule façon de les rendre covariants est d'ajouter un type borné par exemple:
Optional<? extends ArrayList<String>> doesntWork = option;
qui compilerait.
Et quand vous dites que l'étape map
ne devrait rien accomplir, c'est bien, ce n'est pas correct. Regardez la définition de Optional::map
:
public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
Objects.requireNonNull(mapper);
if (!isPresent()) {
return empty();
} else {
return Optional.ofNullable(mapper.apply(value));
}
}
grosso modo ne transforme de Optional<T>
à Optional<U>
...
Dans votre dernier cas, le type de retour du Optional.map
est implicitement déterminée par le type de votre variable works
. Voilà pourquoi il y a une différence.
Votre option.map
a la signature
<ArrayList<?>> Optional<ArrayList<?>> Java.util.Optional.map(Function<? super ArrayList<String>, ? extends ArrayList<?>> mapper)
Donc ça
Optional<? extends ArrayList<?>> doesntWork = option;
compile.