次の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で関数を渡す最も簡単な回避策は何ですか?関数で機能する一般的なソリューションが欲しいのですが任意の数のパラメータを持つ。
編集:Java 8には、以下で説明する従来のソリューションよりも優れた構文がありますか?
JavaでFunction1
を手動でインスタンス化する必要があります。何かのようなもの:
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);
これは Daniel Spiewakの「Java and Scala」の記事 から引用したものです。
scala.runtime
パッケージには、他のアリティ用のAbstractFunction1
という名前の抽象クラスがあります。 Javaから使用するには、次のようにapply
をオーバーライドするだけです。
Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
public String apply(Integer someInt) {
return myFunc(someInt);
}
};
Java 8を使用していて、Java 8のラムダ構文を使用したい場合は、 https://github.com/ scala/scala-Java8-compat 。
私にとって最も簡単な方法は、Javaインターフェースを次のように定義することです。
public interface JFunction<A,B> {
public B compute( A a );
}
次に、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) )
}
}
自然にscalaの最初の定義を使用しますが、Javaの2番目の定義も使用できます。
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);
}
};
}
これが私の解決策である小さなライブラリです: https://github.com/eirslett/sc8
Java 8ラムダをF(...)でラップすると、Scala関数に変換されます。