【问题标题】:Is it possible to use a Java 8 style method references in Scala?是否可以在 Scala 中使用 Java 8 风格的方法引用?
【发布时间】:2015-11-02 20:04:18
【问题描述】:

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

这里是相关代码sn-p。

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 decleration。

【问题讨论】:

  • 注意:Java 没有方法引用。你可以有一个对象,它有一个调用另一个方法的方法(这是 lambdas 实际做的)
  • 我想我对您的评论“Java 没有方法引用”感到困惑。我认为我要做的与官方文档中的 ComparisonProvider 示例没有什么不同(链接:docs.oracle.com/javase/tutorial/java/javaOO/…)。
  • 这个问题基本上是stackoverflow.com/questions/24369449 的副本,简而言之,您可以创建一个从 (T) => Unit 到 EventHandler[T] 的隐式转换并导入该隐式。
  • @angelogenovese 我知道这个问题,但是,我想知道是否可以同时使用方法引用来避免 lambda 语法。我已经编辑了我的问题以反映这一点。
  • ScalaFX 是一个开源项目。有原因阻止您使用它,但没有查看代码以获取使用示例

标签: java scala java-8 javafx-8


【解决方案1】:

如果你想要一个方法引用也将类实例作为参数,例如像 Java 中的String::length,你可以使用(_:String).length,它相当于(s:String) => s.length()

这些类型在 Java 中是 Function<String, Integer>,在 Scala 中是 String => Int

【讨论】:

    【解决方案2】:

    inputController::handleFileSelection 是 Java 语法,它在 Scala 中不受支持或不需要,因为它已经为 lambdas 提供了如下的简短语法:inputController.handleFileSelection _inputController.handleFileSelection(_)inputController.handleFileSelection 也可以工作,具体取决于上下文)。

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

    【讨论】:

    • 当我启用实验功能时,fileButton.setOnAction(inputController.handleFileSelection) 编译时没有错误。但是,当执行此行时,会立即执行 handleFileSelection 方法而不是作为引用传递。我想这就是为什么它仍然是一个实验性功能。
    • 对我有用的是启用实验功能并让 lambda 表达式处理方法引用,如下所示。 fileButton.setOnAction((event: ActionEvent) => inputController.handleFileSelection).
    • 你的意思是(event: ActionEvent) => inputController.handleFileSelection(event)?您评论中的版本确实不应该工作。
    • 或者您的handleFileSelection 方法实际上没有 采用ActionEvent 吗?这将解释它如何可以在没有实际ActionEvent 的情况下立即执行,如您的第一条评论中所述。
    • 在这种情况下inputController.handleFileSelection(_) 或者最坏的情况下inputController.handleFileSelection(_: ActionEvent) 应该也可以工作。
    【解决方案3】:

    你应该传递一个应用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))
    

    【讨论】:

    • 不幸的是,这不起作用。 found : Unit required: javafx.event.EventHandler[javafx.event.ActionEvent] 我可以通过将方法签名更改为 public EventHandler<ActionEvent> handleFileSelection(){ 来使其工作,但这违背了使用方法引用的全部目的。
    • @Mustafa 你为什么不尝试通过inputController?它看起来像一个目标接口的实现,不是吗?
    • @Mustafa 如果你想使用方法参考,我们应该谈谈一些功能(消费者、供应商等)fileButton.setOnAction 期望什么?
    • inputController 将处理来自多个 UI 元素的事件,我想分别处理它们。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多