Cannot make a static reference to the non-static method

1.2k views Asked by At

I read the tutorial for Reference to an instance method of an arbitrary object of a particular type . Here is the link https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html

So I wrote my own code but I am unable to remove error . Arrays.sort(arr, String::compareToIgnoreCase); is a legal statement but Consumer m2 =Myclass::doit; gives an error . How to resolve this error ? Is the concept of Reference to an instance method of an arbitrary object of a particular type applicable to inbuilt classes of java like String ?

Here goes my code

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

interface Myinter {
 void doit(List<String> s);
}
public class Myclass implements Myinter {
    public static void main(String[] args) {
        List<String> obj = new ArrayList<String>();
        obj.add("raj");
        obj.add("gopal");
        obj.add("bhallamudi");
        String arr[] = new String[obj.size()];
        arr = obj.toArray(arr);
        Arrays.sort(arr, String::compareToIgnoreCase);
        for (String s : arr)
            System.out.println(s + " ");

          Consumer<List<String>> m2 =Myclass::doit;
          m2.accept(obj);
    }
    @Override
    public void doit(List<String> s) {
            System.out.println(s);

    }
}
2

There are 2 answers

3
aseychell On

The same rules for applying method references apply to standard Java classes like String and also your own classes. In your example, you have 2 types of usages of method references. 1) Instead of normal invocation doit and 2) Replacing a lambda expression.

  1. The notation in Java 8 Myclass::doit means you are calling the static method doit on Myclass. Instead you have to create an object for Myclass and call it on your object as follows:

    Myclass reallyMyClass = new Myclass();
    
    Consumer<List<String>> m2 = reallyMyClass::doit;
    m2.accept(obj);
    
  2. When using method references to replace a lambda, the notation is slightly different and references can be used using the name of the class. So the usage with String in your example when expanded means:

    Arrays.sort(arr, (s1, str) -> s1.compareToIgnoreCase(str));
    

    and the shorthand version of that replaces the definitions of the lambda parameters and calls the method on s1 using parameter str as the argument to compareToIgnoreCase hence having this:

    Arrays.sort(arr, String::compareToIgnoreCase);
    

For further reference, this blog post is a good read on this subject: https://www.codementor.io/eh3rrera/using-java-8-method-reference-du10866vx

13
Holger On

When you create an unbound reference to an instance method, the receiver instance becomes the first functional argument.

In the case of String::compareToIgnoreCase, you will have two string arguments being passed to Comparator.compare; the method compareToIgnoreCase will be invoked on the first getting the second passed as argument.

Likewise, you would have to use

BiConsumer<Myclass,List<String>> m2 = Myclass::doit;
m2.accept(new MyClass(), obj);

as you can’t invoke the instance method doit without an instance of Myclass. Or, incorporating your interface:

BiConsumer<Myinter,List<String>> m2 = Myinter::doit;
m2.accept(new MyClass(), obj);

Here, an instance of any class implementing Myinter is sufficient.