2017-04-16 3 views
0

J'ai une méthode Java qui possède un paramètre de type interface SerializablePredicate.Comment sérialiser Scala lambda pour interop avec la méthode Java?

@FunctionalInterface 
interface SerializablePredicate<T> extends Predicate<T>, Serializable {} 

Que dois-je faire pour sérialiser un lambda Scala, comme

(x:String) => println(x) 

tel qu'il sera compatible avec la méthode Java.

Actuellement je tente de lancer le lambda

class SomeClass[T](val p:(T=>Boolean)) extends SomeJavaClass[T](p.asInstanceOf[SerializablePredicate[T]]) {} 

Et ceci est la trace de la pile que je reçois ...

Exception in thread "main" java.lang.ClassCastException: Main$$anonfun$1 cannot be cast to io.cognitionbox.core.SerializablePredicate 
at P.<init>(LogicJavaToScalaInterp.scala:11) 
at Main$.delayedEndpoint$Main$1(Main.scala:9) 
at Main$delayedInit$body.apply(Main.scala:3) 
at scala.Function0$class.apply$mcV$sp(Function0.scala:34) 
at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12) 
at scala.App$$anonfun$main$1.apply(App.scala:76) 
at scala.App$$anonfun$main$1.apply(App.scala:76) 
at scala.collection.immutable.List.foreach(List.scala:381) 
at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:35) 
at scala.App$class.main(App.scala:76) 
at Main$.main(Main.scala:3) 
at Main.main(Main.scala) 

Répondre

1

Vous ne pouvez pas lancer ScalaFunction à JavaFunctional, ils sont pas la même chose. mais vous pouvez essayer de le faire comme:

class SomeClass[T](val p:(T=>Boolean)) extends SomeJavaClass[T]((t: T) => p.apply(t)) {} 

Dans le code ci-dessus: (t: T) => p.apply(t), Creat une nouvelle SerializablePredicate<T>JavaFunctionalInterfaceexemple pour la classe SomeJavaClass.

Il est un exemple pour convertir ScalaFunction à JavaFunction:

Foo interface fonctionnelle:

@FunctionalInterface 
public interface Foo<T> { // Define a Java FunctionalInterface 
    T apply(T t); 
} 

classe Bar qui acceptent la fonction Foo comme paramètre:

public class Bar<T> { 
    public Bar(Foo<T> foo) 
} 

Ainsi, dans Scala, nous pouvons passer ScalaFunction à Javaclass par:

class B(c: String => String) extends A((t: String) => c.apply(t)) // convert c of Scala Function to Java Function 
val s: String => String = s => s.toUpperCase 
val b = new B(s) 
+0

Je ne suis pas sûr de ce que vous entendez par "Dans le code ci-dessus: (t: T) => p.apply (t), Créer une nouvelle instance Java FunctionalInterface SerializablePredicate pour la classe SomeJavaClass", pourriez-vous fournir un exemple s'il vous plaît? – newlogic

1

Depuis SerializablePredicate est une interface SAM (une seule méthode abstraite), à ​​Scala 2.12, vous pouvez simplement écrire

new SomeJavaClass(x => ...) 

et le lambda sera compilé en SerializablePredicate. Si vous avez besoin pour soutenir les anciennes versions Scala, vous pouvez créer une conversion implicite:

implicit def makeSerializable[A](p: A => Boolean): SerializablePredicate[A] = new SerializablePredicate[A] { 
    def test(x: A) = p(x) // or whatever Predicate's method is called 
} 

et chaque fois qu'il est dans la portée, vous pouvez passer un lambda aux méthodes/classes qui prennent SerializablePredicate. Notez que dans les deux cas, vous devez vous assurer que le lambda est réellement sérialisable, c'est-à-dire qu'il ne capture aucun objet non sérialisable.

+0

Une idée de comment déléguer à une méthode Java qui renvoie void? – newlogic

+0

L'équivalent Scala de 'void' est' Unit', sauf que c'est un type réel. –