Использование 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 лучший синтаксис, чем классические решения, рассмотренные ниже?
4 ответа:
Вы должны вручную создать экземпляр
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);
Это взято из статьи Дэниела Спивака "взаимодействие между Java и Scala" .
В пакете
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 lambda, проверьте https://github.com/scala/scala-java8-compat .
Самый простой способ для меня-это определить интерфейс 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); } }; }
Вот моя попытка решения, небольшая библиотека: https://github.com/eirslett/sc8
Вы оборачиваете свою лямбду Java 8 в F(...) и затем он преобразуется в функцию Scala.