Использование Scala из Java: передача функций в качестве параметров
Рассмотрим следующий код Scala:
package scala_java
object MyScala {
def setFunc(func: Int => String) {
func(10)
}
}
Теперь в Java я хотел бы использовать MyScala
как:
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);
}
}
Однако вышеупомянутое не работает (как и ожидалось, так как Java не разрешает функциональное программирование). Какое самое легкое обходное решение для передачи функции в Java? Я хотел бы, чтобы общее решение работало с функциями, имеющими произвольное количество параметров.
EDIT: есть ли у Java 8 лучший синтаксис, чем классические решения, обсуждаемые ниже?
Ответы
Ответ 1
Вам нужно вручную создать экземпляр Function1
в Java. Что-то вроде:
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);
Это взято из Daniel Spiewaks "Взаимодействие между Java и Scala" статьи.
Ответ 2
В пакете scala.runtime
существуют абстрактные классы с именем AbstractFunction1
и т.д. для других объектов. Чтобы использовать их с Java, вам нужно только переопределить apply
, например:
Function1<Integer, String> f = new AbstractFunction1<Integer, String>() {
public String apply(Integer someInt) {
return myFunc(someInt);
}
};
Если вы используете Java 8 и хотите использовать синтаксис лямбда Java 8 для этого, посмотрите https://github.com/scala/scala-java8-compat.
Ответ 3
Самый простой способ для меня - определить интерфейс java, например:
public interface JFunction<A,B> {
public B compute( A a );
}
Затем измените код scala, перегрузив setFunc
, чтобы принять также JFunction
объекты, такие как:
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) )
}
}
Естественно, вы используете первое определение из scala, но все же сможете использовать второй из 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);
}
};
}
Ответ 4
Здесь моя попытка решения, небольшая библиотека: https://github.com/eirslett/sc8
Вы завершаете свою лямбду Java 8 в F (...), а затем преобразуете ее в функцию Scala.