简体   繁体   中英

Generics: Upper Bounded Wildcards conversion/casting error

Here is the test:

@Test
public void genericsTest() {
    String s = "x";
    List<? extends String> strings = singletonList(s);
    Optional<Function<String, List<? extends String>>> optionalSelector = Optional.empty();
    optionalSelector.map(selector -> selector.apply(s)).orElse(strings);
}

And here is the error:

java: incompatible types: java.util.List<capture#1 of ? extends java.lang.String> cannot be converted to java.util.List<capture#2 of ? extends java.lang.String>

Of course, it can be fixed using the raw type trick.

    optionalSelector.map(selector -> selector.apply(s)).orElse((List)strings);

But I'd like to understand the cause of this error.

Update :

It's not a duplicate of Lists with wildcards cause Generic voodoo error which is about adding into an upper-bounded wildcard list; this topic is also well described in Wildcard Guidelines .

In my case I'm not trying to add something into the list as you can see above.

Also, the error messages are different.

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>>> Optional<Function<String, List<? extends String>>> to a Optional<List<? extends String>> Optional<List<? extends String>> . Then, with orElse , you're attempting to convert that to a List<? extends String> 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>> 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>> Optional<List<? extends String>> to Optional<? extends List<? extends String>> Optional<? extends List<? extends String>> Optional<? extends List<? extends String>> , with an added ? extends ? 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>> Optional<List<? extends String>> . I can't tell if the compiler's captured type is Optional<? extends List<? extends String>> Optional<? extends List<? extends String>> 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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM