Why does Optional.map make this assignment work?
If you look into the code of map
and follow all the method calls, you'll see that option.map(list -> list)
ends up returning new Optional<>(option.get())
. So you can replace your last assignment with:
Optional<ArrayList<?>> works = new Optional<>(option.get());
This creates a new Optional<ArrayList<?>>
and initializes its value
instance variable (whose type is ArrayList<?>
) with the ArrayList<String>
returned by map.get()
. This is a valid assignment.
Is there some sort of implicit cast going on?
No, map
returns a new Optional
instance. It doesn't cast the original instance on which it was called.
Here's the chain of method calls:
option.map(list -> list)
returns (since option
is not empty)
Optional.ofNullable(mapper.apply(value))
which in your case is the same as
Optional.ofNullable(value)
which returns (since the value is not null):
Optional.of(value)
which returns
new Optional<>(value)
Well the first one does not work because generics are invariant, the only way to make them covariant is to add a bounded type for example:
Optional<? extends ArrayList<String>> doesntWork = option;
that would compile.
And when you say that the map
step should no accomplish anything is well, not correct. Look at the definition of 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));
}
}
roughly speaking it does transform from Optional<T>
to Optional<U>
...