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.
Predicate<? super String> predicate2 = (CharSequence c)
-> c.toString().length() > 2 ;
System.out.println(predicate2.test((CharSequence)"foo")); // capture error
The issue is that predicate2
says it is something which will accept a String
; you're trying to pass it a CharSequence
.
If you change the declaration of the variable to
Predicate<? super CharSequence> predicate2
then it works.
The reason this doesn't work is that you might be passing a MyCharSequence implements CharSequence
to the predicate:
System.out.println(predicate2.test((CharSequence)new MyCharSequence()));
This shouldn't be accepted, because the type of the predicate2
variable says it should only expect to be given an instance of String
. The compiler only sees the type of the actual parameter as CharSequence
, so it can't distinguish between "this is a String
" (would be OK) and "this is a MyCharSequence
" (wouldn't be OK).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With