527

In Java, how can one pass a function as an argument to another function?

Ola Ström
  • 4,136
  • 5
  • 22
  • 41
Jason
  • 5,451
  • 4
  • 19
  • 12
  • 5
    http://stackoverflow.com/questions/4685435/what-is-the-cloest-thing-to-a-function-pointer-in-java – Cratylus Jan 13 '11 at 21:40
  • 3
    you can pass an Object which you have defined some method you want to use as parameter – starcorn Jan 13 '11 at 22:01
  • More answers on how to use a Lambda function, or pass it as a parameter: [simple example parameter as a function java](https://stackoverflow.com/a/53219950/7747942). – Sylhare Nov 09 '18 at 04:41
  • Define Consumer, Supplier, Predicate or Function as type of argument in another function, e.g. `Function func`, and pass your function like `this::foo`, and then use it like: `func.apply(param)` – Deqing Jan 18 '23 at 22:11

8 Answers8

586

Java 8 and above

Using Java 8+ lambda expressions, if you have a class or interface with only a single abstract method (sometimes called a SAM type), for example:

public interface MyInterface {
    String doSomething(int param1, String param2);
}

then anywhere where MyInterface is used, you can substitute a lambda expression:

class MyClass {
    public MyInterface myInterface = (p1, p2) -> { return p2 + p1; };
}

For example, you can create a new thread very quickly:

new Thread(() -> someMethod()).start();

And use the method reference syntax to make it even cleaner:

new Thread(this::someMethod).start();

Without lambda expressions, these last two examples would look like:

new Thread(new Runnable() { someMethod(); }).start();

Before Java 8

A common pattern would be to 'wrap' it within an interface, like Callable, for example, then you pass in a Callable:

public T myMethod(Callable<T> func) {
    return func.call();
}

This pattern is known as the Command Pattern.

Keep in mind you would be best off creating an interface for your particular usage. If you chose to go with callable, then you'd replace T above with whatever type of return value you expect, such as String.

In response to your comment below you could say:

public int methodToPass() { 
        // do something
}

public void dansMethod(int i, Callable<Integer> myFunc) {
       // do something
}

then call it, perhaps using an anonymous inner class:

dansMethod(100, new Callable<Integer>() {
   public Integer call() {
        return methodToPass();
   }
});

Keep in mind this is not a 'trick'. It's just java's basic conceptual equivalent to function pointers.

amalloy
  • 89,153
  • 8
  • 140
  • 205
jk.
  • 7,572
  • 2
  • 25
  • 22
  • Would you be able to show what exactly would be passed into the following: public void DansMethod(int i, ){ } – Jason Jan 13 '11 at 21:43
  • 4
    I would need a much more simpler solution. Can anyone help? – TomeeNS Jan 03 '14 at 00:27
  • Is it possible to create a base AsyncTask class and pass your desire method in it. can we create this scenario .. kindly elaborate.. – Zar E Ahmer May 15 '14 at 13:31
  • 33
    So for the 100+ methods I need to do this for, I need 100+ interfaces. ggreatttttt =/ – Alexander May 22 '14 at 23:05
  • 3
    @XAleXOwnZX you could use a single Callable<> interface, but you would need to create 100+ anonymous inner classes of type Callable<>. Of course, you can now use Java 8 lambda expressions to simplify this, which was not available when I wrote this response. – jk. May 24 '14 at 19:19
  • 2
    @TomeeNS - here is a simple example, where foo() is the function passed as a parameter, and demo() is the function that takes a function as a parameter. void demo(final Callable func){ func.call(); } void foo(){ return null; } demo(new Callable() {public Void call() {return foo();}} – videogameboy76 Oct 23 '14 at 20:19
  • It is a trick, it's just an idiomatic trick. :) Java doesn't consider methods or functions to be first-class objects. – weberc2 Jan 03 '15 at 02:26
  • @videogameboy76 translating your example to the answer given here: how do you actually call `myFunc` in `dansMethod`? `Callable` appears to be defined in `java.util.concurrent.Callable` as an interface, but only defines a `call` function which takes no parameters... how do you pass the parameters? – Michael Sep 12 '15 at 17:46
  • @jk. Lets say `MethodToPass` relied on a value belonging to it's class, and that it was passed to a function/class in another object. If the value it relied on changed somehow, would `MethodToPass` reflect this inside of the function/class it got passed to? If not, how could one achieve this functionality? – t-bone Dec 07 '19 at 22:00
  • Does passing from a runnable not work? – juztcode Sep 10 '20 at 09:25
131

You could use Java reflection to do this. The method would be represented as an instance of java.lang.reflect.Method.

import java.lang.reflect.Method;

public class Demo {

    public static void main(String[] args) throws Exception{
        Class[] parameterTypes = new Class[1];
        parameterTypes[0] = String.class;
        Method method1 = Demo.class.getMethod("method1", parameterTypes);

        Demo demo = new Demo();
        demo.method2(demo, method1, "Hello World");
    }

    public void method1(String message) {
        System.out.println(message);
    }

    public void method2(Object object, Method method, String message) throws Exception {
        Object[] parameters = new Object[1];
        parameters[0] = message;
        method.invoke(object, parameters);
    }

}
The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
bdoughan
  • 147,609
  • 23
  • 300
  • 400
  • 10
    @Tim Bender: or inside the "mirror" perhaps? – sova Jan 13 '11 at 21:45
  • 1
    Ah Java idiosynchrasies... What would we do without them? – SyntaxT3rr0r Jan 13 '11 at 23:21
  • 1
    What if your function has no parameters and returns nothing? – AloneInTheDark Mar 14 '14 at 10:07
  • 1
    @AloneInTheDark: If you look at [the documentation](https://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object,%20java.lang.Object...)) you'll notice that the arguments to `invoke` are optional. Also, `void` methods return `null`. __P.S. And for your particular case: [suggested reading](https://en.wikipedia.org/wiki/Loneliness#Treatments_and_prevention). – Daniel Apr 20 '15 at 17:48
105

Lambda Expressions

To add on to jk.'s excellent answer, you can now pass a method more easily using Lambda Expressions (in Java 8). First, some background. A functional interface is an interface that has one and only one abstract method, although it can contain any number of default methods (new in Java 8) and static methods. A lambda expression can quickly implement the abstract method, without all the unnecessary syntax needed if you don't use a lambda expression.

Without lambda expressions:

obj.aMethod(new AFunctionalInterface() {
    @Override
    public boolean anotherMethod(int i)
    {
        return i == 982
    }
});

With lambda expressions:

obj.aMethod(i -> i == 982);

Here is an excerpt from the Java tutorial on Lambda Expressions:

Syntax of Lambda Expressions

A lambda expression consists of the following:

  • A comma-separated list of formal parameters enclosed in parentheses. The CheckPerson.test method contains one parameter, p, which represents an instance of the Person class.

    Note: You can omit the data type of the parameters in a lambda expression. In addition, you can omit the parentheses if there is only one parameter. For example, the following lambda expression is also valid:

    p -> p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    
  • The arrow token, ->

  • A body, which consists of a single expression or a statement block. This example uses the following expression:

    p.getGender() == Person.Sex.MALE 
        && p.getAge() >= 18
        && p.getAge() <= 25
    

    If you specify a single expression, then the Java runtime evaluates the expression and then returns its value. Alternatively, you can use a return statement:

    p -> {
        return p.getGender() == Person.Sex.MALE
            && p.getAge() >= 18
            && p.getAge() <= 25;
    }
    

    A return statement is not an expression; in a lambda expression, you must enclose statements in braces ({}). However, you do not have to enclose a void method invocation in braces. For example, the following is a valid lambda expression:

    email -> System.out.println(email)
    

Note that a lambda expression looks a lot like a method declaration; you can consider lambda expressions as anonymous methods—methods without a name.


Here is how you can "pass a method" using a lambda expression:

Note: this uses a new standard functional interface, java.util.function.IntConsumer.

class A {
    public static void methodToPass(int i) { 
        // do stuff
    }
}
import java.util.function.IntConsumer;

class B {
    public void dansMethod(int i, IntConsumer aMethod) {
        /* you can now call the passed method by saying aMethod.accept(i), and it
        will be the equivalent of saying A.methodToPass(i) */
    }
}
class C {
    B b = new B();

    public C() {
        b.dansMethod(100, j -> A.methodToPass(j));   //Lambda Expression here
    }
}

The above example can be shortened even more using the :: operator.

public C() {
    b.dansMethod(100, A::methodToPass);
}
Community
  • 1
  • 1
The Guy with The Hat
  • 10,836
  • 8
  • 57
  • 75
19

Thanks to Java 8 you don't need to do the steps below to pass a function to a method, that's what lambdas are for, see Oracle's Lambda Expression tutorial. The rest of this post describes what we used to have to do in the bad old days in order to implement this functionality.

Typically you declare your method as taking some interface with a single method, then you pass in an object that implements that interface. An example is in commons-collections, where you have interfaces for Closure, Transformer, and Predicate, and methods that you pass implementations of those into. Guava is the new improved commons-collections, you can find equivalent interfaces there.

So for instance, commons-collections has org.apache.commons.collections.CollectionUtils, which has lots of static methods that take objects passed in, to pick one at random, there's one called exists with this signature:

static boolean exists(java.util.Collection collection, Predicate predicate) 

It takes an object that implements the interface Predicate, which means it has to have a method on it that takes some Object and returns a boolean.

So I can call it like this:

CollectionUtils.exists(someCollection, new Predicate() {
    public boolean evaluate(Object object) { 
        return ("a".equals(object.toString());
    }
});

and it returns true or false depending on whether someCollection contains an object that the predicate returns true for.

Anyway, this is just an example, and commons-collections is outdated. I just forget the equivalent in Guava.

Nathan Hughes
  • 94,330
  • 19
  • 181
  • 276
7

Java supports closures just fine. It just doesn't support functions, so the syntax you're used to for closures is much more awkward and bulky: you have to wrap everything up in a class with a method. For example,

public Runnable foo(final int x) {
  return new Runnable() {
    public void run() {
      System.out.println(x);
    }
  };
}

Will return a Runnable object whose run() method "closes over" the x passed in, just like in any language that supports first-class functions and closures.

amalloy
  • 89,153
  • 8
  • 140
  • 205
5

I used the command pattern that @jk. mentioned, adding a return type:

public interface Callable<I, O> {

    public O call(I input);   
}
c0der
  • 18,467
  • 6
  • 33
  • 65
Aram Kocharyan
  • 20,165
  • 11
  • 81
  • 96
  • Similar to JavaFx [Callback

    ](https://docs.oracle.com/javase/8/javafx/api/javafx/util/Callback.html)

    – c0der Oct 27 '18 at 03:07
4

I know this is a rather old post but I have another slightly simpler solution. You could create another class within and make it abstract. Next make an Abstract method name it whatever you like. In the original class make a method that takes the new class as a parameter, in this method call the abstract method. It will look something like this.

public class Demo {

    public Demo(/.../){

    }

    public void view(Action a){
        a.preform();
    }

    /**
     * The Action Class is for making the Demo
     * View Custom Code
     */
    public abstract class Action {

        public Action(/.../){

        }

        abstract void preform();
    }
}

Now you can do something like this to call a method from within the class.

/...
Demo d = new Demo;
Action a = new Action() {

    @Override
    void preform() {
        //Custom Method Code Goes Here
    }
};

/.../
d.view(a)

Like I said I know its old but this way I think is a little easier. Hope it helps.

c0der
  • 18,467
  • 6
  • 33
  • 65
Zatran
  • 51
  • 5
  • Your solution does not provide an easier method. Using an already existing interface to perform this task is more intuitive than creating your own custom abstract class. While there is nothing wrong with your solution, and it does provide an alternative, I don't see the value or reason for using this approach over an interface. – Jyro117 Aug 07 '13 at 17:31
  • From what I saw on the Interface examples it only lets you use return values. This is more oriented for if you wanted a void result. In certain cases this alternate could have some beneficial uses. – Zatran Aug 07 '13 at 18:16
  • 2
    Callable works fine for that situation, or simply using Runnable. It is more common to use an interface, even if you made a custom one, as it provides a more flexible hierarchy. – Jyro117 Aug 07 '13 at 20:50
-15

Java does not (yet) support closures. But there are other languages like Scala and Groovy which run in the JVM and do support closures.

Claude
  • 453
  • 2
  • 9
  • 22
    Java has supported [closures](http://en.wikipedia.org/wiki/Closure_%28computer_science%29) since version 1.0. You're probably talking about lambda expressions or at least functions defined without being syntactically contained in an explicit class definition. – thejoshwolfe Oct 30 '11 at 19:18