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

Jus*_*s12 44 java scala scala-java-interop

请考虑以下Scala代码:

package scala_java
object MyScala {
  def setFunc(func: Int => String) {
    func(10)
  }
}
Run Code Online (Sandbox Code Playgroud)

现在在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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,上述方法不起作用(正如预期的那样,因为Java不允许函数式编程).在Java中传递函数最简单的解决方法是什么?我想要一个通用的解决方案,适用于具有任意数量参数的函数.

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

Set*_*sue 67

scala.runtime包中,有AbstractFunction1其他arities 命名的抽象类等.要从Java中使用它们,您只需要覆盖apply,如下所示:

Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};
Run Code Online (Sandbox Code Playgroud)

如果您使用的是Java 8并希望使用Java 8 lambda语法,请查看https://github.com/scala/scala-java8-compat.

  • 谢谢!你的答案是最有帮助的!尝试实现Function1,Java告诉我必须实现许多方法 - Function1具有几种基本类型的特化. (2认同)

Jea*_*let 27

您必须Function1在Java中手动实例化.就像是:

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);
Run Code Online (Sandbox Code Playgroud)

这取自Daniel Spiewak的"Interop Between Java和Scala"一文.

  • 请务必在评论中查看文章和Daniel的`FunUtils`类,这有助于删除`$ tag`和`compose`所需的一些样板. (4认同)

par*_*tic 7

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

public interface JFunction<A,B> {
  public B compute( A a );
}
Run Code Online (Sandbox Code Playgroud)

然后修改你的scala代码,重载setFunc以接受JFunction对象,例如:

object MyScala {
  // API for scala
  def setFunc(func: Int => String) {
    func(10)
  }
  // API for java
  def setFunc(jFunc: JFunction[Int,String]) {
    setFunc( (i:Int) => jFunc.compute(i) )
  }
}
Run Code Online (Sandbox Code Playgroud)

您自然会使用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);
      }
    };

}
Run Code Online (Sandbox Code Playgroud)