javamethod-reference

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 (i.e. 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?)


Solution

  • 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();
        }
    }