Übergabe einer Scala-Funktion an eine Java 8-Methode

18

Der folgende Scala-Code funktioniert und kann an eine Java-Methode übergeben werden, die eine Funktion erwartet. Gibt es einen saubereren Weg, dies zu tun? Hier ist mein erster Durchgang:

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] = ???
}

Hier ist mein zweiter Durchgang - er verwendet einen generischen Wrapper für die Java-8-Funktionsschnittstelle, um die Scala-Syntax zu vereinfachen:

// 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)

Können wir es besser machen?

Besteht als Folge die Möglichkeit, dass Scala eines Tages den aufrufdynamischen Op-Code wie Java 8 für seine erstklassige Funktionsanwendung verwendet? Wird das alles auf magische Weise funktionieren oder muss es noch eine syntaktische Konvertierung geben?

GlenPeterson
quelle

Antworten:

10

Sie können die Konvertierung implizit machen:

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

Sie sollten eigentlich nicht überschreiben müssen composeund andThen, aber vielleicht kennt der Scala-Compiler Java 8-Standardschnittstellenmethoden noch nicht. (BEARBEITEN: es sollte in 2.10.3 funktionieren.)

Außerdem sollten Sie in der Lage sein, Scala-Lambdas (dh x => ...) Functionund andere SAM-Typen in Scala 2.11 und Java 8-Lambdas zuzuweisen Function1. (BEARBEITEN: Dies wurde tatsächlich in Scala 2.12 hinzugefügt, nicht in 2.11.)

Alexey Romanov
quelle
you should be able to assign Scala lambdas- Das bedeutet, dass in Scala 2.11 eine Scala-Funktion als Argument für ein Java8-Lambda übergeben werden kann?
Kevin Meredith
Ob es als Argument übergeben werden kann, hängt vom Lambda-Typ ab. wenn es zB java.util.function.Consumer[scala.Function1[Integer, String]]ist, kann es auch vor 2.11 gemacht werden.
Alexey Romanov