BiConsumer and method reference of one parameter

Niko Gambt :

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.


  1. Why does the code compile without complain if the second argument is an Experiment instance, and why does it not compile otherwise?
  2. Why is it valid to pass a method reference of only one parameter as an argument that expects BiConsumer?
Eran :

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.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=305894&siteId=1