Function Pointers in Java

Java does not provide function pointers in the same way C/C++ does.

Instead of passing a function pointer f, you create an object with an instance method f and pass the object instead. With lambdas and method refernecs the syntactical overhead for doing this is close to zero.

Using a method reference

class Example {
    // Method that takes a "method" as argument
    static void exampleMethod(Runnable toRun) {
        toRun.run();
    }

    // Method to pass
    static void sayHello() {
        System.out.println("Hello");
    }

    public static void main(String[] args) {
        exampleMethod(Example::sayHello);  // prints "Hello"
    }
}

Using a lambda

You may also invoke the exampleMethod above as follows:

exampleMethod(() -> System.out.println("Hello"));

For similar examples with different method signatures, see the Lambda Cheat Sheet.

Using ordinary objects

The above examples requires Java 8. Here’s how to do it in Java 7:

exampleMethod(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello");
    }
});

Using reflection

You can use reflection to pass actual Method objects and Method.invoke to invoke the method. This is not recommended and often seen as a hack / last resort.

import java.lang.reflect.Method;

class Example {

    static void exampleMethod(Method toInvoke) throws Exception {
        // null as callee for static methods
        toInvoke.invoke(null);
    }

    public static void sayHello() {
        System.out.println("Hello");
    }

    public static void main(String[] args) throws Exception {
        // prints "Hello"
        exampleMethod(Example.class.getMethod("sayHello"));
    }
}       

A real world use case

Let’s take a look at a more realistic use case.

Example: Storing "methods" in a hash map
import java.util.*;

class Example {

    public static void main(String[] args) {
        Map<Character, Runnable> commands = new HashMap<>();

        // Populate commands map
        commands.put('h', () -> System.out.println("Type h or q"));
        commands.put('q', () -> System.exit(0));

        while (true) {
            // Print menu
            System.out.println("Menu");
            System.out.println("h) Help");
            System.out.println("q) Quit");

            // User input
            char key = new Scanner(System.in).nextLine().charAt(0);

            // Run selected command
            if (commands.containsKey(key))
                commands.get(key).run();
        }
    }
}

Comments

Be the first to comment!