Java8 Function apply method with a implementation

Viewed 104

My codes are here. My puzzle is in the main method of Test.java, the first case prints the result using its implementation, while another as a normal lambda expression prints what it actually is. Also I wanna know if they have the same method signature causing the problem.

public class Test {
    public static void main(String[] args) {
        
        Function<ApplyService, Class<? extends ApplyService>> f1 = ApplyService::run;

        System.out.println(f1.apply(new ApplyService1())); 
        // class Function.ApplyService1 -  It's strange, got a result with 'ApplyService1.run'

        //        
        Function<ApplyService, Class<? extends ApplyService>> f2 = Abc::run2;

        System.out.println(f2.apply(new ApplyService1())); // null as wish
    }
}

interface Abc {
    static Class<? extends ApplyService> run2(ApplyService app) {
        return null;
    }
}

interface ApplyService {
    default Class<? extends ApplyService> run() {
        return null;
    }
}

class ApplyService1 implements ApplyService{
    public Class< ? extends ApplyService> run(){
        return this.getClass();
    }
}
2 Answers

The first function Function<ApplyService, Class<? extends ApplyService>> f1 = ApplyService::run; is equivalent to :

Function<ApplyService, Class<? extends ApplyService>> f1 = apService -> apService.run();

So, while passing an object of type ApplyService1 the implemented method in ApplyService1 is invoked.

But the second function Function<ApplyService, Class<? extends ApplyService>> f2 = Abc::run2; is equivalent to :

Function<ApplyService, Class<? extends ApplyService>> f2 = apService -> Abc.run2(apService);

Since Abc::run2 is static method reference, the input ApplyService object is passed to the run2 method.

ApplyService::run is a "Reference to an instance method of an arbitrary object of a particular type" as described here. Notice how run is an instance method, so you would need an instance to call it. You didn't specify any instance of ApplyService in the method reference (you just said ApplyService::run), so instead, when you invoke the method reference, the first argument you pass to apply is used as the instance on which to call the instance method.

In this case, new ApplyService1() is the instance on which you call run, so when you do:

f1.apply(new ApplyService1())

you are actually calling:

new ApplyService1().run()

Notice how the argument becomes the instance on which you call the method.

In the case of Abc::run2, it is a "Reference to a static method", so none of that "parameter becoming the instance on which you call the method" shenanigan happens, and it works as you expect.

Related