Passing a Scala function to a Java 8 method
https://softwareengineering.stackexchange.com/questions/231420
-
02-10-2020 - |
Question
The following Scala code works and can be passed to a Java method expecting a function. Is there a cleaner way to do this? Here's my first pass:
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] = ???
}
Here's my second pass - it uses a generic wrapper for the Java-8 Function interface to make the Scala syntax simpler:
// 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)
Can we do better?
As a follow-up, is there any chance that Scala will someday use the invoke-dynamic op-code as Java 8 does for its first-class function application? Will that make everything magically work, or will there still need to be a syntactic conversion?
La solution
You can make the conversion implicit:
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
You shouldn't actually need to override compose
and andThen
, but maybe Scala compiler doesn't know about Java 8 default interface methods yet. (EDIT: it should work in 2.10.3.)
Also, you should be able to assign Scala lambdas (i.e. x => ...
) to Function
and any other SAM types in Scala 2.11, and Java 8 lambdas to Function1
. (EDIT: this actually got added in Scala 2.12, not 2.11.)