closures - What's the nearest substitute for a function pointer in Java?

ID : 10131

viewed : 33

Tags : javaclosuresfunction-pointersjava

Top 5 Answer for closures - What's the nearest substitute for a function pointer in Java?

vote vote

91

Anonymous inner class

Say you want to have a function passed in with a String param that returns an int.
First you have to define an interface with the function as its only member, if you can't reuse an existing one.

interface StringFunction {     int func(String param); } 

A method that takes the pointer would just accept StringFunction instance like so:

public void takingMethod(StringFunction sf) {    int i = sf.func("my string");    // do whatever ... } 

And would be called like so:

ref.takingMethod(new StringFunction() {     public int func(String param) {         // body     } }); 

EDIT: In Java 8, you could call it with a lambda expression:

ref.takingMethod(param -> bodyExpression); 
vote vote

84

For each "function pointer", I'd create a small functor class that implements your calculation. Define an interface that all the classes will implement, and pass instances of those objects into your larger function. This is a combination of the "command pattern", and "strategy pattern".

@sblundy's example is good.

vote vote

73

When there is a predefined number of different calculations you can do in that one line, using an enum is a quick, yet clear way to implement a strategy pattern.

public enum Operation {     PLUS {         public double calc(double a, double b) {             return a + b;         }     },     TIMES {         public double calc(double a, double b) {             return a * b;         }     }      ...       public abstract double calc(double a, double b); } 

Obviously, the strategy method declaration, as well as exactly one instance of each implementation are all defined in a single class/file.

vote vote

65

You need to create an interface that provides the function(s) that you want to pass around. eg:

/**  * A simple interface to wrap up a function of one argument.  *   * @author rcreswick  *  */ public interface Function1<S, T> {     /**     * Evaluates this function on it's arguments.     *      * @param a The first argument.     * @return The result.     */    public S eval(T a);  } 

Then, when you need to pass a function, you can implement that interface:

List<Integer> result = CollectionUtilities.map(list,         new Function1<Integer, Integer>() {            @Override            public Integer eval(Integer a) {               return a * a;            }         }); 

Finally, the map function uses the passed in Function1 as follows:

   public static <K,R,S,T> Map<K, R> zipWith(Function2<R,S,T> fn,           Map<K, S> m1, Map<K, T> m2, Map<K, R> results){       Set<K> keySet = new HashSet<K>();       keySet.addAll(m1.keySet());       keySet.addAll(m2.keySet());        results.clear();        for (K key : keySet) {          results.put(key, fn.eval(m1.get(key), m2.get(key)));       }       return results;    } 

You can often use Runnable instead of your own interface if you don't need to pass in parameters, or you can use various other techniques to make the param count less "fixed" but it's usually a trade-off with type safety. (Or you can override the constructor for your function object to pass in the params that way.. there are lots of approaches, and some work better in certain circumstances.)

vote vote

53

Method references using the :: operator

You can use method references in method arguments where the method accepts a functional interface. A functional interface is any interface that contains only one abstract method. (A functional interface may contain one or more default methods or static methods.)

IntBinaryOperator is a functional interface. Its abstract method, applyAsInt, accepts two ints as its parameters and returns an int. Math.max also accepts two ints and returns an int. In this example, A.method(Math::max); makes parameter.applyAsInt send its two input values to Math.max and return the result of that Math.max.

import java.util.function.IntBinaryOperator;  class A {     static void method(IntBinaryOperator parameter) {         int i = parameter.applyAsInt(7315, 89163);         System.out.println(i);     } } 
import java.lang.Math;  class B {     public static void main(String[] args) {         A.method(Math::max);     } } 

In general, you can use:

method1(Class1::method2); 

instead of:

method1((arg1, arg2) -> Class1.method2(arg1, arg2)); 

which is short for:

method1(new Interface1() {     int method1(int arg1, int arg2) {         return Class1.method2(arg1, agr2);     } }); 

For more information, see :: (double colon) operator in Java 8 and Java Language Specification ยง15.13.

Top 3 video Explaining closures - What's the nearest substitute for a function pointer in Java?

Related QUESTION?