使用Java中的Scala:将函数作为参数传递

使用Java中的Scala:将函数作为参数传递,java,scala,scala-java-interop,Java,Scala,Scala Java Interop,考虑以下Scala代码: package scala_java object MyScala { def setFunc(func: Int => String) { func(10) } } 现在在Java中,我想使用MyScala作为: package scala_java; public class MyJava { public static void main(String [] args) { MyScala.setFunc(myFun

考虑以下Scala代码:

package scala_java
object MyScala {
  def setFunc(func: Int => String) {
    func(10)
  }
}
现在在Java中,我想使用
MyScala
作为:

package scala_java;
public class MyJava {
    public static void main(String [] args) {
        MyScala.setFunc(myFunc);  // This line gives an error
    }
    public static String myFunc(int someInt) {
        return String.valueOf(someInt);
    }
}
但是,上述方法不起作用(正如预期的那样,因为Java不允许函数式编程)。在Java中传递函数最简单的解决方法是什么?我想要一个通用的解决方案,它可以处理具有任意数量参数的函数


编辑:Java8是否有比下面讨论的经典解决方案更好的语法

对我来说,最简单的方法是定义一个java接口,如:

public interface JFunction<A,B> {
  public B compute( A a );
}
您自然会使用scala的第一个定义,但仍然可以使用java的第二个定义:

public class MyJava {
  public static void main(String [] args) {
    MyScala.setFunc(myFunc);  // This line gives an error
  }

  public static final JFunction<Integer,String> myFunc = 
    new JFunction<Integer,String>() {
      public String compute( Integer a ) {
        return String.valueOf(a);
      }
    };

}
公共类MyJava{
公共静态void main(字符串[]args){
MyScala.setFunc(myFunc);//此行给出一个错误
}
公共静态最终函数myFunc=
新JFunction(){
公共字符串计算(整数a){
返回字符串.valueOf(a);
}
};
}

您必须在Java中手动实例化
函数1
。比如:

final Function1<Integer, String> f = new Function1<Integer, String>() {
    public int $tag() {
        return Function1$class.$tag(this);
    }

    public <A> Function1<A, String> compose(Function1<A, Integer> f) {
        return Function1$class.compose(this, f);
    }

    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};
MyScala.setFunc(f);
final function1f=new Function1(){
公共int$tag(){
返回函数1$class.$tag(此);
}

public.

scala.runtime
包中,有一些抽象类被命名为
AbstractFunction1
,等等,用于其他算术运算。要从Java中使用它们,只需覆盖
apply
,如下所示:

Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};
function1f=newAbstractFunction1(){
公共字符串应用(整数someInt){
返回myFunc(someInt);
}
};

如果您使用的是Java 8,并且希望使用Java 8 lambda语法,请查看。

以下是我尝试的解决方案,一个小库:


将Java8lambda封装在F(…)然后它被转换成一个Scala函数。

一定要在注释中查看文章和Daniel的
FunUtils
类,这有助于删除
$tag
compose
所需的一些样板文件。这非常有用。我以前看过这篇文章,但没有阅读注释。@Jean Philippellet就像Daniel Spiewak的链接被破坏一样。@Gautham看看Seth的答案,它比我的好。Daniel的链接现在大约有10年了…@Jus12。谢谢,这是固定的。实际上,Scala的函数已经在幕后实现为SAM类型。因此,你可以直接实现
函数n
(根据Jean-Philippe的回答)并且不需要介绍您自己的
JFunction
类型。我不同意,虽然您可以直接从java实例化scala函数,但生成的代码相当难看。如果您只是想偶尔访问一些scala代码,这是可以的。但是如果您想提供java API,您可以通过添加一些更高级别的接口和scala me来获得更好的代码为java API设计的方法。例如,它将有助于解决缺少隐式解析的问题。只要您有Scala源代码,这是很好的。@paradigmatic-即使如此,仍然有一个强有力的论据,就是使用Google guava的
函数
类型,而不是重新发明轮子。谢谢!您的answer是最有帮助的!试图实现Function1时,Java告诉我必须实现几十种方法——Function1对几种基本类型进行了专门化。这就是您要寻找的答案:)另外请注意,如果您是为Android或iOS编译,您将无法使用scala-java8-compat,因为retrolambda可以仅修改您的源文件。源文件也没有lambda桥类(JFunction0等)因为它们是从sbt直接生成到.class文件的代码。可能有一种方法可以将.class文件包含在项目中,retrolambda可以在其中修改它们,但我还没有投入精力去弄清楚这一点。如果你的函数参数不带参数,你需要用BoxedUnit键入一个AbstractFunction1;同样,如果它是如果要转换单位,则需要在lambda中键入带有BoxedUnit的返回valies并返回BoxedUnit.Unit。即
new AbstractFunction1(){public BoxedUnit apply(BoxedUnit Unit){/*…*/return BoxedUnit.Unit;}
Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};