I accept that due to the lower bounded wildcard, this predicate should not accept a superclass of String
without an explicit cast.[1,2] This question is rather about type safety enforcement in the lambda's parameter list. Given the second block fails compilation, why is the first allowed to compile without a warning? It appears that in the first case, despite the lambda's parameter declaration, CharSequence
is being cast to String
to satisfy predicate's boundary constraint.
Predicate<? super String> predicate1 = (CharSequence c)
-> c.toString().length() > 2 ;
System.out.println(predicate1.test("foo")); // compiles
Predicate<? super String> predicate2 = (CharSequence c)
-> c.toString().length() > 2 ;
System.out.println(predicate2.test((CharSequence)"foo")); // capture error
error: method test in interface Predicate<T> cannot be applied to given types;
out.println(predicate2.test((CharSequence)"foo"));
^
required: CAP#1
found: CharSequence
reason: argument mismatch; CharSequence cannot be converted to CAP#1
where T is a type-variable:
T extends Object declared in interface Predicate
where CAP#1 is a fresh type-variable:
CAP#1 extends Object super: String from capture of ? super String
Thanks for the work on this. The issue appears to be an assumption that the lambda and the generic process would forced to consume a CharSequence
. However, it's now clear that String
can be submitted to the lambda without a compiler error, so what's happening in the first case and a String
is being submitted to both processes. It's no surprise that the generics process is ignoring the content of the lambda.