Почему Optional.map заставляет это назначение работать?

Optional<ArrayList<String>> option = Optional.of(new ArrayList<>());

Optional<ArrayList<?>> doesntWork = option;

Optional<ArrayList<?>> works = option.map(list -> list);

Первая попытка назначения не компилируется, а вторая с map не компилируется. Такое ощущение, что map самом деле ничего не должна делать, но по какой-то причине она превращает мой Optional<ArrayList<String>> в Optional<ArrayList<?>>. Есть ли какой-то неявный актерский состав?

Ответ 1

Если вы посмотрите код map и выполните все вызовы метода, вы увидите, что option.map(list → list) конечном итоге возвращает new Optional<>(option.get()). Таким образом, вы можете заменить свое последнее назначение на:

Optional<ArrayList<?>> works = new Optional<>(option.get());

Это создает новый Optional<ArrayList<?>> и инициализирует его переменную экземпляра value (тип ArrayList<?>) С ArrayList<String> возвращаемым map.get(). Это действительное назначение.

Есть ли какой-то неявный актерский состав?

Нет, map возвращает новый Optional экземпляр. Он не использует оригинальный экземпляр, на котором он был вызван.

Вот цепочка вызовов методов:

option.map(list -> list)

возвращает (так как option не пуста)

Optional.ofNullable(mapper.apply(value))

который в вашем случае такой же, как

Optional.ofNullable(value)

который возвращает (так как значение не является нулевым):

Optional.of(value)

который возвращается

new Optional<>(value)

Ответ 2

Ну, первый не работает, потому что генерики являются инвариантными, единственный способ сделать их ковариантными, это добавить ограниченный тип, например:

 Optional<? extends ArrayList<String>> doesntWork = option; 

это будет компилироваться.

И когда вы говорите, что шаг map не должен ничего делать, это хорошо, не правильно. Посмотрите на определение 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));
    }
}

грубо говоря, он трансформируется из Optional<T> в Optional<U>...

Ответ 3

Линия:

Optional<ArrayList<?>> works = option.map(list → list);

равно:

Optional<ArrayList<?>> works = option.map(new Function<ArrayList<String>, ArrayList<?>>() {
    @Override
    public ArrayList<?> apply(ArrayList<String> list) {
        return list;
    }
});

Вы можете думать об этом как:

ArrayList<String> strings = new ArrayList<>();
ArrayList<?> list = strings;
Optional<ArrayList<?>> works = Optional.ofNullable(list);

Ответ 4

Ваш option.map имеет подпись

<ArrayList<?>> Optional<ArrayList<?>> java.util.Optional.map(Function<? super ArrayList<String>, ? extends ArrayList<?>> mapper)

Так это

Optional<? extends ArrayList<?>> doesntWork = option;

делает компиляцию

Ответ 5

В последнем случае тип возвращаемого значения метода Optional.map неявно определяется типом вашей переменной works. Вот почему есть разница.