java - ejemplos - curso scala parte 2
Usar Scala desde Java: pasar funciones como parĂ¡metros (4)
Considere el siguiente código de Scala:
package scala_java
object MyScala {
def setFunc(func: Int => String) {
func(10)
}
}
Ahora en Java, me hubiera gustado usar MyScala
como:
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);
}
}
Sin embargo, lo anterior no funciona (como se esperaba, ya que Java no permite la programación funcional). ¿Cuál es la solución más fácil para pasar una función en Java? Me gustaría una solución genérica que funcione con funciones que tengan un número arbitrario de parámetros.
EDITAR: ¿Java 8 tiene una sintaxis mejor que las soluciones clásicas que se describen a continuación?
Aquí está mi intento de una solución, una pequeña biblioteca: https://github.com/eirslett/sc8
Envuelve su Java 8 lambda en F (...) y luego se convierte en una función de Scala.
Debe instanciar manualmente una Function1
en Java. Algo como:
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);
Esto está tomado del artículo de Daniel Spiewak "Interop Between Java and Scala" .
En el paquete scala.runtime
, hay clases abstractas llamadas AbstractFunction1
y otras para aries. Para utilizarlos desde Java, solo necesita anular la apply
, así:
Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
public String apply(Integer someInt) {
return myFunc(someInt);
}
};
Si tiene Java 8 y desea utilizar la sintaxis lambda de Java 8 para esto, consulte https://github.com/scala/scala-java8-compat .
La forma más fácil para mí es definir una interfaz Java como:
public interface JFunction<A,B> {
public B compute( A a );
}
Luego modifique su código scala, sobrecargando setFunc
para aceptar también objetos JFunction
tales como:
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) )
}
}
Naturalmente usará la primera definición de scala, pero aún podrá usar la segunda de 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);
}
};
}