简体   繁体   中英

Using Scala from Java: passing functions as parameters

Consider the following Scala code:

package scala_java
object MyScala {
  def setFunc(func: Int => String) {
    func(10)
  }
}

Now in Java, I would have liked to use MyScala as:

package scala_java;
public class MyJava {
    public static void main(String [] args) {
        MyScala.setFunc(myFunc);  // This line gives an error
    }
    public static String myFunc(int someInt) {
        return String.valueOf(someInt);
    }
}

However, the above does not work (as expected since Java does not allow functional programming). What is the easiest workaround to pass a function in Java? I would like a generic solution that works with functions having arbitrary number of parameters.

EDIT: Does Java 8 have any better syntax than the classic solutions discussed below?

In the scala.runtime package, there are abstract classes named AbstractFunction1 and so on for other arities. To use them from Java you only need to override apply , like this:

Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};

If you're on Java 8 and want to use Java 8 lambda syntax for this, check out https://github.com/scala/scala-java8-compat .

You have to manually instantiate a Function1 in Java. Something like:

final Function1<Integer, String> f = new Function1<Integer, String>() {
    public int $tag() {
        return Function1$class.$tag(this);
    }

    public <A> Function1<A, String> compose(Function1<A, Integer> f) {
        return Function1$class.compose(this, f);
    }

    public String apply(Integer someInt) {
        return myFunc(someInt);
    }
};
MyScala.setFunc(f);

This is taken from Daniel Spiewak's “Interop Between Java and Scala” article .

The easiest way for me is to defined a java interface like:

public interface JFunction<A,B> {
  public B compute( A a );
}

Then modify your scala code, overloading setFunc to accept also JFunction objects such as:

object MyScala {
  // API for scala
  def setFunc(func: Int => String) {
    func(10)
  }
  // API for java
  def setFunc(jFunc: JFunction[Int,String]) {
    setFunc( (i:Int) => jFunc.compute(i) )
  }
}

You will naturally use the first definition from scala, but still be able to use the second one from java:

public class MyJava {
  public static void main(String [] args) {
    MyScala.setFunc(myFunc);  // This line gives an error
  }

  public static final JFunction<Integer,String> myFunc = 
    new JFunction<Integer,String>() {
      public String compute( Integer a ) {
        return String.valueOf(a);
      }
    };

}

Here's my attempt at a solution, a little library: https://github.com/eirslett/sc8

You wrap your Java 8 lambda in F(...) and then it's converted to a Scala function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM