是否可以在 Scala 中使用 Java 8 样式的方法引用?

2022-09-01 12:10:06

我正在Scala中开发一个JavaFX8应用程序,但我不知道如何将方法引用传递给事件处理程序。为了澄清,我不是在使用ScalaFX库,而是直接在JavaFX之上构建我的应用程序。

下面是相关的代码片段。

InputController.java(我用Java编写了这个测试类来隔离问题以仅使用方法引用)

public class InputController {
    public void handleFileSelection(ActionEvent actionEvent){
        //event handling code
    }

    public InputController() {
        //init controller
    }
}

这有效(Java)

InputController inputController = new InputController();
fileButton.setOnAction(inputController::handleFileSelection);

这不起作用(Scala)

val inputController = new InputController
fileButton.setOnAction(inputController::handleFileSelection)

这是来自编译器(Scala 2.11.6)的错误消息。

Error:(125, 45) missing arguments for method handleFileSelection in class Main;
follow this method with '_' if you want to treat it as a partially applied function
    fileButton.setOnAction(inputController::handleFileSelection)
                                            ^

如果我使用Scala 2.12.0-M2,我会收到不同的错误消息。

Error:(125, 45) missing argument list for method handleFileSelection in class Main
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `handleFileSelection _` or `handleFileSelection(_)` instead of `handleFileSelection`.
    fileButton.setOnAction(inputController::handleFileSelection)
                                            ^

有没有一种原生方式可以让Scala利用Java 8中引入的方法引用?我知道隐式转换方法使用lambda表达式,但我想知道是否有一种方法可以使用类似于Java 8的方法引用而无需使用lambda递减。


答案 1

inputController::handleFileSelection是Java语法,这在Scala中不受支持或不需要,因为它已经有一个像这样的lambda的简短语法:or(也可以工作,这取决于上下文)。inputController.handleFileSelection _inputController.handleFileSelection(_)inputController.handleFileSelection

但是,在Java中,当需要任何SAM(单抽象方法)接口时,您可以使用lambda和方法引用,并且就是这样一个接口。在版本2.11之前的Scala中,这是完全不允许的,在2.11中,有对将lambdas与SAM接口一起使用的实验性支持,必须使用scalac标志启用,从2.12开始,它是完全支持的,不需要启用。EventHandler-Xexperimental


答案 2

您应该传递应用一个类型参数的函数:ActionEvent

val button = new Button()
val inputController = new InputController()

def handler(h: (ActionEvent => Unit)): EventHandler[ActionEvent] =
  new EventHandler[ActionEvent] {
    override def handle(event: ActionEvent): Unit = h(event)
  }

button.setOnAction(handler(inputController.handleFileSelection))

推荐