web-dev-qa-db-fra.com

Pourquoi Optional.map fait-il fonctionner cette affectation?

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?

36
Carl Minden

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)
25
Eran

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>...

10
Eugene

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.

0
dpr

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.

0
user11044402