I defined following methods.
class Some {
void doSome(Consumer<? super Other> consumer) {
}
<T extends Collection<? super Other>> T doSome(T collection) {
doSome(collection::add); // <<<<<<<<<<<<<<<<<<<
return collection;
}
}
Now the javac
complains.
java: reference to getAttributes is ambiguous both method doSome(java.util.function.Consumer<? super Other>) in ... and method doSome(T) in ...Some match
Why javac
couldn't discriminate Consumer
and Collection
?
This is because collection::add
is not pertinent to applicability when invoking doSome(T)
.
Specifically, it is this case:
If
m
is a generic method and the method invocation does not provide explicit type arguments, an explicitly typed lambda expression or an exact method reference expression for which the corresponding target type (as derived from the signature ofm
) is a type parameter ofm
.
m
here is doSome
, which is a generic method. collection:add
is an exact method reference. Its target type is (T) -> boolean
(a function that takes in a T
and returns boolean
). (T) -> boolean
includes the type parameter T
, so it is not pertinent to applicability.
"Pertinent to applicability" is Java's way of deciding what argument expressions to consider during overload resolution. It simply doesn't consider some arguments (those that are not pertinent to applicability), because that would make overload resolution too complicated.
Since collection::add
is practically "ignored", doSome(T)
is also an applicable method, in addition to doSome(Consumer)
, which is obviously applicable. Therefore, there is an overload resolution ambiguity.
I would just add a cast to fix this:
doSome((Consumer<? super Other>)collection::add);
A cast expression is pertinent to applicability.
See also this similar question which is about implicitly typed lambda expressions, which are also not pertinent to applicability.