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);