Почему 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
. Вот почему есть разница.