Java 8 Method Reference to non-static method

前端 未结 6 1275
悲哀的现实
悲哀的现实 2020-12-29 10:11

Why this doesn\'t work? I get compiler error \"Cannot make static reference to the non static method print...\"

public class Chapter3 {
    public void print         


        
相关标签:
6条回答
  • 2020-12-29 10:36

    If you mismatch types of the function and the objects you are generating the function from, you will see the non static error. For example, this line of code will not compile because the function expects a Foo as the type it is acting on, but the function is for a Foobar:

    Function<Foo, Bar> func = Foobar::getBar;
    

    It doesn't just deal with when its in a for loop or any other argument nor does it have to deal with "what is in scope". It's a type mismatch error that java mislabeled when using the new function objects. Compare this to what happens when you construct other generics:

    List<Foo> list = new ArrayList<Bar>();
    

    That line of code will fail to compile with the error "Incompatible Types". Even better is that this code will also fail with incompatible types instead despite also dealing with functional objects in nearly the exact same way:

    public void test() {
        Function<Foo, Double> test2 = Foo::getDouble;
        //fails with Incompatible types
        test3(test2);
    }
    
    
    public void test3(Function<Foobar, Double> function) {
        //who cares
    }
    

    My best suggestion is when you start having this error, pull out the function declaration to a new line and you should be able to see what the actual issue is. Why java chose "non-static method cannot be referenced from a static context" is beyond me.

    0 讨论(0)
  • 2020-12-29 10:40

    Regardless of whether you use method references, lambda expressions or ordinary method calls, an instance method requires an appropriate instance for the invocation. The instance may be supplied by the function invocation, e.g. if forEach expected a BiConsumer<Chapter3,String> it worked. But since forEach expects a Consumer<String> in your case, there is no instance of Chapter3 in scope. You can fix this easily by either, changing Chapter3.print to a static method or by providing an instance as target for the method invocation:

    public class Chapter3 {
        public void print(String s) {
            System.out.println(s);
        }
        public static void main(String[] args) {
            Arrays.asList("a", "b", "c").forEach(new Chapter3()::print);
        }
    }
    

    Here, the result of new Chapter3(), a new instance of Chapter3, will be captured for the method reference to its print method and a Consumer<String> invoking the method on that instance can be constructed.

    0 讨论(0)
  • 2020-12-29 10:41

    You could make your print function static, this way you don't need an instance to call it on:

    public class Chapter3 {
        public static void print(String s) {
            System.out.println(s);
        }
        public static void main(String[] args) {
            Arrays.asList("a", "b", "c").forEach(Chapter3::print);
        }
    }
    
    0 讨论(0)
  • 2020-12-29 10:45

    forEach accepts a Consumer<? super T> (its signature is default void forEach(Consumer<? super T> action)), which is a functional interface with a method accept(T t) that has a single argument.

    When you pass a non-static method reference of a method that has an argument, you actually have two arguments - the this reference to the Chapter3 instance and the String argument. This doesn't match what forEach expects.

    0 讨论(0)
  • 2020-12-29 10:49

    I think I got it now. What's in the Stream is of type String therefore I can't call print on a String intance...

    For example this works

    public class Chapter3 {
    final String value;
    
    public Chapter3(String value) {
        this.value = value;
    }
    
    public void print() {
        System.out.println(value);
    }
    
    public static void main(String[] args) {
        Arrays.asList(new Chapter3("a"), new Chapter3("b")).forEach(Chapter3::print);
    }
    }
    
    0 讨论(0)
  • 2020-12-29 10:55

    Just in case if you are trying to apply an instance method from the same object where your code runs

    Arrays.asList("a", "b", "c").forEach(this::print);
    
    0 讨论(0)
提交回复
热议问题