Home > Enterprise >  List of non-static method references in Java
List of non-static method references in Java

Time:11-27

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?)

CodePudding user response:

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

CodePudding user response:

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