There appears to be something wrong with the multiple levels of type inference here. With this line:
optionalSelector.map(selector -> selector.apply(s)).orElse(strings);
With the call to map
, you're attempting to convert the original Optional<Function<String, List<? extends String>>>
to a Optional<List<? extends String>>
. Then, with orElse
, you're attempting to convert that to a List<? extends String>
. It seems reasonable.
I can get it to compile without resorting to casting to raw types, by giving the intermediate step an explicit type.
Optional<List<? extends String>> intermedSelector = optionalSelector.map(selector -> selector.apply(s));
intermedSelector.orElse(strings);
This shows that if the compiler can infer the result of the call to map
to be a Optional<List<? extends String>>
, then the call to orElse
will compile.
However, I can change the explicit type to something where the declaration of intermedSelector
compiles, but the call to orElse
does not compile. I've changed the explicit type of interMedSelector
from Optional<List<? extends String>>
to Optional<? extends List<? extends String>>
, with an added ? extends
.
Optional<? extends List<? extends String>> intermedSelector = optionalSelector.map(selector -> selector.apply(s));
intermedSelector.orElse(strings);
The error here is similar to the one you're getting:
J.java:26: error: incompatible types: List<CAP#1> cannot be converted to CAP#2
List<? extends String> result = intermedSelector.orElse(strings);
^
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends String from capture of ? extends String
CAP#2 extends List<? extends String> from capture of ? extends List<? extends String>
With your code, the compiler must be inferring something unexpected, yet related to, Optional<List<? extends String>>
. I can't tell if the compiler's captured type is Optional<? extends List<? extends String>>
or something else, but that appears to be why you're getting the error.
My solution
Optional<List<? extends String>> intermedSelector = optionalSelector.map(selector -> selector.apply(s));
intermedSelector.orElse(strings);
can be expressed in one statement, if I supply the proper type parameter to the call to map
, so the compiler doesn't infer something unexpected.
optionalSelector.<List<? extends String>>map(selector -> selector.apply(s)).orElse(strings);