1

This following code compiles ok:

List<String> strList = List.of("foo", "bar");
List<?> genList = strList;

But a nested list does not:

List<List<String>> strList = List.of(List.of("foo", "bar"));
List<List<?>> genList = strList;

Why is this? And if I need to do this, what is the 'correct' way to do it?

The use case is that I have a method that returns one of a number of different collections where the element type is itself generic with a different defined type for each possible return value, where the return value is dependent on the argument passed in. At the moment, as a workaround, I am assigning the result to a variable where the type is the collection type with a wildcard (i.e. List<?>>) and performing the full cast at the end of the method (i.e. return (List<List<T>>) result), where the return

  • 8
    A `List` is a `List>` but a `List>` is not a `List>` for the same reason as `Integer` is a `Number` but a `List` is not a `List`, because you could add a `Long` to a `List` which would be horrible if it actually refers to your `List`. Just generalize it; a `List` is not a `List` and it doesn’t matter whether “`Sub` and `Super`” are “`Integer` and `Number`” or “`List` and `List>`” – Holger Mar 18 '22 at 17:23

1 Answers1

2
List<List<String>> strList = List.of(List.of("foo", "bar"));
List<? extends List<?>> genList = strList;

This will do what you want. Mind you, you can't add() anything to genList (the compiler can't know that whatever you're adding is legit for the type of list it's actually holding), and anything you get() from the list will be of type List<?> (the compiler can't tell you what's actually in there.)

You could then cast the retrieved object to List< String > (which you "know" it is), but the compiler will give you an unchecked type conversion warning to say, "If this isn't really a list of strings as you seem to believe, don't blame me. I wash my hands of whatever happens later on."