简体   繁体   中英

List of non-static method references in Java

I am trying to use a list of function references as a lookup table (avoiding the need for a long switch statement). The code worked for a list of static methods, but when I tried to use non-static (ie instance) methods in the list, Java gives several errors regarding the types not matching.

Here is a minimal example:

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;

public class MethodReferences {
    // My original list of static references
    private final static List<Function<Integer, Integer>> lookupTable = Arrays.asList(MethodReferences::f1, MethodReferences::f2);

    // This doesn't work
    // private final List<Function<Integer, Integer>> lookupTable = Arrays.asList(MethodReferences::f3, MethodReferences::f4);

    private static int f1(int x) { return x * 2; }

    private static int f2(int x) { return x * 3; }

    private int f3(int x) { return x * 2; }

    private int f4(int x) { return x * 3; }

    public void run() {
        System.out.println(lookupTable.get(1).apply(3));
    }

    public static void main(String[] args) {
        MethodReferences testClass = new MethodReferences();

        testClass.run();
    }
}

The errors I received were all for the line containing the non-static definition:

Type mismatch: cannot convert from List<Object> to List<Function<Integer,Integer>>

and:

The target type of this expression must be a functional interface

I tried using this:: instead of MethodReferences:: before the function names. The code then compiled, but when it runs, nothing happens, probably because this has to be used within non-static functions. I then moved the initialisation of the array (still using this:: to within the class constructor, but it continued to produce no output when run.

I've checked through the documentation and tutorials on method references in Java, but I cannot find an examples of creating references to instance methods within the class it is defined in (and I cannot find any examples of lists of function references either).

I'm aware that in the main method, you can do testClass::f1 , but for my specific situation (not the example code) I do not even have a main class (the class is instantiated by another library), so this approach isn't possible. The methods have to be non-static because I need to be able to modify instance variables within them.


Edit: It turns out that using this:: does work for the example code, although I am still unsure as to why it is valid (surely you can only use this within a non-static function?)

For instance method references which use the ClassName::functionName format, instead of instanceName::functionName , you also need to pass the specific instance of the class to the function when calling .apply() .

This means that your method references are actually need to be a BiFunction<MethodReferences, Integer, Integer> , even though there is only one explicit parameter to the function.

When calling the method, you also need to pass this into apply:

import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;

public class MethodReferences {
    // To refer to non-static methods by class name,
    // you must pass in the instance explicitly:
    private final List<BiFunction<MethodReferences, Integer, Integer>> lookupTable = Arrays.asList(MethodReferences::f3, MethodReferences::f4);

    private int f3(int x) {
        return x * 2;
    }

    private int f4(int x) {
        return x * 3;
    }

    public void run() {
        // We need to pass this in, because it isn't implicit
        // for ClassName::functionName references:
        System.out.println(lookupTable.get(1).apply(3));
    }

    public static void main(String[] args) {
        MethodReferences testClass = new MethodReferences();

        testClass.run();
    }
}

You need to use BiFunction instead of Function . The first argument is the implicit this argument.

public class MethodReferences {
    private final static List<BiFunction<MethodReferences, Integer, Integer>> lookupTable
        = Arrays.asList(MethodReferences::f3, MethodReferences::f4);

    private int f3(int x) { return x * 2; }
    private int f4(int x) { return x * 3; }

    public void run() {
        System.out.println(lookupTable.get(1).apply(this, 3));
    }

    public static void main(String[] args) {
        MethodReferences testClass = new MethodReferences();
        testClass.run();
    }
}

output:

9

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM