What is the difference between the following method references,
BiPredicate<List<String>,String> contains1 = List<String>::contains;
BiPredicate<List<String>,String> contains2 = List::<String>contains;
BiPredicate<List<String>,String> contains3 = List<String>::<String>contains;
Do the cases have special names? Is there any example similar to the usage?
First of all, that is called a type witness (in the official Oracle Tutorial) or TypeArguments (in the JLS Sec 15.12) and you are effectively helping the compiler with such constructs.
One example:
private static void test(Callable<Object> call) {
}
private static void test(Runnable run) {
}
static class Gen<T> {
}
And call it via test(Gen::new);
(this will fail, never mind why), but the point is that you add a type witness to help the compiler, so this would work
test(Gen<String>::new);
So when you write List<String>
, you have added a type witness for the target type - List
that is; in the second case you are adding one for the method contains
- but it's not generic, so it is ignored.
In:
BiPredicate<List<String>, String> contains2 = List::<String>contains;
<String>
is a type argument to a non-generic List.contains
method1.
While in:
BiPredicate<List<String>, String> contains1 = List<String>::contains;
<String>
is a type argument to a List
.
1 - In this particular case a type argument is ignored according to the JLS §15.12.2.1:
A non-generic method may be potentially applicable to an invocation that supplies explicit type arguments. In such a case, the type arguments will simply be ignored.
Here's what Intellij tells me about them:
BiPredicate<List<String>, String> contains1 = List<String>::contains;
Explicit type arguments can be inferred
BiPredicate<List<String>, String> contains2 = List::<String>contains;
Type arguments are redundant for the non-generic method reference
If you were to split these up into their respective lambda functions, I believe you'd see the following:
BiPredicate<List<String>, String> contains1 = (List<String> strings, String o) -> strings.contains(o);
BiPredicate<List<String>, String> contains2 = (strings, o) -> strings.<String>contains(o);
As we know, (List<String> strings, String o)
can be replaced by (strings, o)
and <String>
on the second line is unneeded (as String#contains
isn't generic), so it's safe to assume that both method references are equivalent.
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