Передача функции Scala в метод Java 8

18

Следующий код Scala работает и может быть передан методу Java, ожидающему функцию. Есть ли более чистый способ сделать это? Вот мой первый проход:

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

Вот мой второй проход - он использует универсальную оболочку для интерфейса функций Java-8, чтобы упростить синтаксис 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)

Можем ли мы сделать лучше?

В качестве продолжения, есть ли шанс, что когда-нибудь Scala будет использовать динамический код вызова invoke, как Java 8 для своего первоклассного функционального приложения? Будет ли это все магическим образом работать, или все же потребуется синтаксическое преобразование?

GlenPeterson
источник

Ответы:

10

Вы можете сделать преобразование неявным:

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

На самом деле вам не нужно переопределять composeи andThen, но, возможно, компилятор Scala еще не знает о методах интерфейса по умолчанию в Java 8. (РЕДАКТИРОВАТЬ: он должен работать в 2.10.3.)

Кроме того, вы должны иметь возможность назначать лямбды Scala (т.е. x => ...) Functionи любые другие типы SAM в Scala 2.11 и лямбды Java 8 Function1. (РЕДАКТИРОВАТЬ: это фактически было добавлено в Scala 2.12, а не 2.11.)

Алексей романов
источник
you should be able to assign Scala lambdas- Это означает, что в Scala 2.11 функцию Scala можно передать в качестве аргумента для лямбды Java8?
Кевин Мередит
Может ли оно быть передано в качестве аргумента, зависит от типа лямбды; если это, например, java.util.function.Consumer[scala.Function1[Integer, String]]то это можно сделать и до 2.11.
Алексей Романов