在Java中,如何将一个函数作为另一个函数的参数传递?


当前回答

Java很好地支持闭包。它只是不支持函数,所以您习惯的闭包语法更加笨拙和笨重:您必须用一个方法将所有内容包装在一个类中。例如,

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

将返回一个Runnable对象,其run()方法“关闭”传入的x,就像在任何支持一级函数和闭包的语言中一样。

其他回答

多亏了Java 8,你不需要执行下面的步骤来将一个函数传递给一个方法,这就是lambdas的作用,请参阅Oracle的Lambda表达式教程。这篇文章的其余部分描述了我们过去为了实现这个功能而不得不做的事情。

通常情况下,您将方法声明为带有单个方法的某个接口,然后传入实现该接口的对象。一个例子是common -collections,其中有Closure、Transformer和Predicate的接口,以及传递这些接口实现的方法。Guava是新的改进的公共集合,你可以在那里找到等价的接口。

例如,commons-collections有org。apache。commons。collections。collectionutils,它有很多静态方法,可以接收传入的对象,随机抽取一个,有一个叫exists,带有这个签名

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

它接受一个实现接口Predicate的对象,这意味着它必须有一个接受object并返回布尔值的方法。

所以我可以这样调用它:

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

它返回true或false,这取决于someCollection是否包含一个谓词为其返回true的对象。

无论如何,这只是一个例子,而common -collections已经过时了。我只是忘了番石榴的等价物。

我使用的命令模式是@jk。提到,添加一个返回类型:

public interface Callable<I, O> {

    public O call(I input);   
}

Java 8及以上版本

使用Java 8+ lambda表达式,如果你有一个类或接口只有一个抽象方法(有时称为SAM类型),例如:

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

那么在任何使用MyInterface的地方,你都可以替换一个lambda表达式:

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

例如,你可以快速创建一个新线程:

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

并使用方法引用语法使其更加清晰:

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

如果没有lambda表达式,最后两个例子将如下所示:

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

Java 8之前

一个常见的模式是将它“包装”在一个接口中,例如Callable,然后传入一个Callable:

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

这个模式被称为命令模式。

请记住,您最好为特定的用途创建一个接口。如果您选择使用callable,那么您可以将上面的T替换为您期望的任何类型的返回值,例如String。

对于你下面的评论,你可以说:

public int methodToPass() { 
        // do something
}

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

然后调用它,可能使用匿名内部类:

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

记住,这不是一个“把戏”。它只是java中基本概念上的函数指针。

Java很好地支持闭包。它只是不支持函数,所以您习惯的闭包语法更加笨拙和笨重:您必须用一个方法将所有内容包装在一个类中。例如,

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

将返回一个Runnable对象,其run()方法“关闭”传入的x,就像在任何支持一级函数和闭包的语言中一样。

Java(目前)不支持闭包。但是还有其他语言,如Scala和Groovy,它们运行在JVM中,并且确实支持闭包。