Pasar una función Scala a un método Java 8


18

El siguiente código Scala funciona y se puede pasar a un método Java que espera una función. ¿Hay una forma más limpia de hacer esto? Aquí está mi primer pase:

val plusOne = new java.util.function.Function[Int,Int] {
  override def apply(t:Int):Int = t + 1

  override def andThen[V](after:function.Function[_ >: Int, _ <: V]):
    function.Function[Int, V] = ???

  override def compose[V](before:function.Function[_ >: V, _ <: Int]):
    function.Function[V, Int] = ???
}

Aquí está mi segundo paso: utiliza un contenedor genérico para la interfaz de la función Java-8 para simplificar la sintaxis de Scala:

// Note: Function1 is Scala's functional interface,
// Function (without the 1) is Java 8's.
case class JavaFunction1[U,V](f:Function1[U,V]) extends Function[U,V] {
  override def apply(t: U): V = f(t)
  override def compose[T](before:Function[_ >: T, _ <: U]):
    Function[T, V] = ???
  override def andThen[W](after:Function[_ >: V, _ <: W]):
    Function[U, W] = ???
}

val plusOne = JavaFunction1((x:Int) => x + 1)
val minusOne = JavaFunction1((x:Int) => x - 1)

¿Podemos hacerlo mejor?

Como seguimiento, ¿hay alguna posibilidad de que Scala algún día use el código de operación dinámico de invocación como lo hace Java 8 para su aplicación de función de primera clase? ¿Eso hará que todo funcione mágicamente, o todavía tendrá que haber una conversión sintáctica?

Respuestas:


10

Puede hacer que la conversión sea implícita:

implicit def toJavaFunction[U, V](f:Function1[U,V]): Function[U, V] = new Function[U, V] {
  override def apply(t: U): V = f(t)

  override def compose[T](before:Function[_ >: T, _ <: U]):
    Function[T, V] = toJavaFunction(f.compose(x => before.apply(x)))

  override def andThen[W](after:Function[_ >: V, _ <: W]):
    Function[U, W] = toJavaFunction(f.andThen(x => after.apply(x)))
}

implicit def fromJavaFunction[U, V](f:Function[U,V]): Function1[U, V] = f.apply

En realidad, no debería necesitar anular composey andThen, pero tal vez el compilador Scala aún no conoce los métodos de interfaz predeterminados de Java 8. (EDITAR: debería funcionar en 2.10.3.)

Además, debería poder asignar Scala lambdas (es decir x => ...) Functiony cualquier otro tipo de SAM en Scala 2.11, y Java 8 lambdas a Function1. (EDITAR: esto realmente se agregó en Scala 2.12, no 2.11.)


you should be able to assign Scala lambdas- Esto significa que, en Scala 2.11, ¿se puede pasar una función Scala como argumento para un Lambda Java8?
— Kevin Meredith

Si se puede pasar como argumento depende del tipo de lambda; si es, por ejemplo java.util.function.Consumer[scala.Function1[Integer, String]], se puede hacer antes de 2.11 también.
— Alexey Romanov
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.