Why is it legal to pass a method reference of one parameter as an argument of expected type BiConsumer
whose abstract method requires two arguments?
Example:
class Experiment {
private String name;
public Experiment(String name) {
this.name = name;
}
public void oneParamMethod(Object o) {
System.out.println(this.name + " and " + o);
}
public <T, S> void executeBiConsumer(BiConsumer<T, S> biCon, T in1, S in2) {
biCon.accept(in1, in2);
}
public static void main(String[] args) {
// notice that the name is "INSTANCE", but it won't be printed out
Experiment exp = new Experiment("INSTANCE");
// executeBiConsumer expects a functional of two params but is given a method
// reference of one param. HOW IS THIS LEGAL?
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
}
}
Output:
PARAM and 999
Let's change the invocation such that the second argument is not an instance of Experiment
as follows:
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
Now, it won't compile.
Experiment
instance, and why does it not compile otherwise?BiConsumer
?A method reference referencing an instance method having one argument actually has two arguments - the first argument is implicit - the instance on which the method is executed.
Experiment::oneParamMethod
is equivalent to (Experiment e, Object o) -> e.oneParamMethod(o)
.
The BiConsumer<T, S>
you are passing to executeBiConsumer
is a BiConsumer<Experiment,Object>
, which means it must receive an instance of Experiment
as the first argument of the accept
method.
Therefore
exp.executeBiConsumer(Experiment::oneParamMethod, new Experiment("PARAM"), 999);
is valid, but
exp.executeBiConsumer(Experiment::oneParamMethod, new String("INVALID"), 999);
is not.
Here's a relevant JLS reference (15.13.1):
Second, given a targeted function type with n parameters, a set of potentially applicable methods is identified:
If the method reference expression has the form ReferenceType :: [TypeArguments] Identifier, the potentially applicable methods are the member methods of the type to search that have an appropriate name (given by Identifier), accessibility, arity (n or n-1), and type argument arity (derived from [TypeArguments]), as specified in §15.12.2.1.
Two different arities, n and n-1, are considered, to account for the possibility that this form refers to either a static method or an instance method.
Your targeted function type - BiConsumer
- has 2 parameters. Therefore the potentially applicable methods are the member methods of the type to search (Experiment
) that have the appropriate name (oneParamMethod
) and arity 2 or 1 (i.e. 1 or 2 arguments). This includes your public void oneParamMethod(Object o)
method.