Подтвердить что ты не робот

Использование 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 лучший синтаксис, чем классические решения, обсуждаемые ниже?

4b9b3361

Ответ 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.