Search code examples
javamethod-reference

java 8 method reference calling non static method in a static way


I am learning method references in Java 8. I learnt that we can define functional interface method with either lambda or method reference. Method reference is a way of telling "there exist a similar method with same signature of functional interface method, you can call it". Further if that similar looking method exists as a static method, we call it using its class name. Or if it exists as non static way, then we will call it with object.

I am confused with below code.. EatSomething class has non-static similarToEat method, then why it is being called like a static method?

import java.util.function.*;

public class Test {
    public static void main(String[] args) {
        Test test = new Test();
        EatSomething es = new EatSomething();
        
        Function <EatSomething,String> ff1 = EatSomething::similarToEat; //here.. similarToEat is a non-static method, then why do I need to call it using class name?
        Function <EatSomething,String> ff2 = (EatSomething eat)->eat.similarToEat();
        Function <EatSomething,String> ff3 = es::eatOverloaded;
        
        
        System.out.println(test.process(ff1));
        
    }

    private String process(Function<EatSomething,String> func) {
        EatSomething es = new EatSomething();
        return func.apply(es);
    }
}


class EatSomething{
    public String similarToEat() {
        return "eat lightning, and crap thunder ";
    }
    
    public String eatOverloaded(EatSomething es) {
        return es.similarToEat();
    }

}

I am totally confused with this. Why should't I call similarToEat using object. Why do I have to use class name here? I can easily relate ff2 and ff3 objects in above code. Really confused with ff1.

One more piece of code..

interface MyCustomFunction{  
    String test(String abc);  
}  
public class MethodReference {  
     
    public static void main(String[] args) {  
        MethodReference mr = new MethodReference();
        MyCustomFunction func = String::toUpperCase; //here again. Why are we calling toUpperCase with its class name when its a non-static method
        System.out.println(mr.processs(func));
    }  
    public String processs(MyCustomFunction obj) {
        
        return obj.test("abc");
    }
}  

Solution

  • You can call similarToEat using object, you will just get not a Function <EatSomething,String> but functional interface with zero-arg method like Callable/Runnable/Supplier since an instance of EatSomething is already defined by that object.

    Here is Oracle documentation with types of method references:

    Kind Syntax
    Reference to a static method ContainingClass::staticMethodName.
    Reference to an instance method of a particular object containingObject::instanceMethodName
    Reference to an instance method of an arbitrary object of a particular type ContainingType::methodName

    Look at examples:

        // denotes a method of any EatSomething instance that is not defined yet
        Function<EatSomething, String> ff1 = EatSomething::similarToEat; // thus we get a function from EatSomething to String
        // denotes a method of already specified EatSomething object
        Supplier<String> ff2 = es::similarToEat; // here we get a function without any argument
        Callable<String> ff3 = es::similarToEat; // it could be another FunctionalInterface with no-arg method
        
        ff1.apply(new EatSomething()); // we could provide any EatSomething object
        ff2.get(); // will execute similarToEat exactly against the es object
        ff3.call(); // will execute similarToEat exactly against the es object
    

    What if EatSomething have a static method?

    class EatSomething {
        public static String eatSomethingStaticMethod() {
            return "";
        }
    }
    

    Then taking method reference with a class name would return no-arg functional interface:

        Supplier<String> ff4 = EatSomething::eatSomethingStaticMethod;
        Callable<String> ff5 = EatSomething::eatSomethingStaticMethod;