When one function creates a generic result such as List<Integer>
, code with a call to another function which accepts a similar but non-matching generic type such as List<? super String>
will unexpectedly compile successfully when the result from the first function is passed inline.
Consider the following code:
import java.util.Collections;
import java.util.List;
class ListTest
{
static void consumeList(List<? super String> lst) {};
static <T> List<T> createList(T value) {
return Collections.singletonList(value);
}
void doIt() {
List<Integer> ilst = createList(1);
consumeList(ilst); // Does not compile. As expected. ("incompatible types: List<Integer> cannot be converted to List<? super String>")
var ilst2 = createList(1);
consumeList(ilst2); // Does not compile. As expected. ("incompatible types: List<Integer> cannot be converted to List<? super String>")
consumeList(createList(1)); // Compiles. Why???
}
}
The question is: Why does the last line compile? The compile error that is yielded by the other calls to "consumeList()" appears absolutely precise and successfully prevents me from a runtime disaster. Why does the compiler fail to provide the same level of protection with the last call?
Compiler was javac 17.0.7.