在 JavaFX WorkerStateEvent 上编译 lambda 时出错

Error compiling lambda on JavaFX WorkerStateEvent

此代码无法使用 javac JDK8 编译器进行编译。

public class Test extends Application {

    public static void main(String[] args) {
        launch(Test.class);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Service service = new Service() {
            @Override
            protected Task createTask() {
                return null;
            }
        };
        service.setOnFailed(event -> System.out.println(event.getSource().getException().toString()));
    }
}

错误是

java: cannot find symbol
symbol: method getException()
location: class java.lang.Object

IntelliJ 告诉我一切正常,如果我在 event.getSource() 上手动添加强制转换,编译工作正常,但 Intellij 告诉我强制转换是多余的。

是否存在 Intellij 错误?我使用的是最新版本的 Intellij Ultimate (14.1.1)。

setOnFailed的签名是

public final void setOnFailed(EventHandler<WorkerStateEvent> value)

所以你需要提供一个EventHandler<WorkerStateEvent>WorkerStatEvent has the method public Worker getSource() that returns a javafx.concurrent.Worker. Your lambda effectively just provides an EventHandler<javafx.event.Event>. The method getSource() of javafx.event.Event 只是返回一个 java.util.EventObject,它没有 WorkerStateEvent 有的方法 getException()

使用泛型:

final EventHandler<WorkerStateEvent> handler = event ->
  System.out.println(event.getSource().getException().toString());
service.setOnFailed(handler);

编辑:

用普通 javac 编译非通用版本会抛出同样的错误:

src/Whosebugfx/WhosebugFX.java:29: error: cannot find symbol
        final EventHandler handler = event -> System.out.println(event.getSource().getException().toString());
                                                                                  ^
  symbol:   method getException()
  location: class Object
Note: src/Whosebugfx/WhosebugFX.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

所以这不是 IDE 问题。

对于这个具体案例,我实际上会以不同的方式编写。您已经知道触发事件的来源是什么;它是您注册侦听器的 service。所以你可以做

service.setOnFailed(event ->
        System.out.println(service.getException().toString());

我不太明白为什么编译器不能从你的代码中推断出类型,但如果你正确地键入服务,为它的泛型类型提供一个参数,那么它编译得很好:

import javafx.application.Application;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.stage.Stage;


public class ServiceTest extends Application{

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        Service<Void> service = new Service<Void>() {
            @Override
            protected Task<Void> createTask() {
                return null;
            }
        };
        service.setOnFailed(event ->
            System.out.println(event.getSource().getException().toString()));
    }

}

您的代码中显然有足够的信息供编译器推断 event 属于 WorkerStateEvent 类型,这应该允许您调用 event.getSource().getException()。我认为当您使用原始类型 (Service) 而不是一般类型的对象 (Service<Void> 等) 时,类型推断会因某种原因而失败。