简体   繁体   中英

Error compiling lambda on JavaFX WorkerStateEvent

This code does not compile with the javac JDK8 compiler.

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()));
    }
}

The error is

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

IntelliJ tells me yet that all is OK and if I manually add a cast on event.getSource() , the compilation works but Intellij tells me that the cast is redundant.

Is there an Intellij bug ? I use the latest version of Intellij Ultimate (14.1.1).

For this specific case, I would actually write this differently. You already know what the source of the event that is fired is; it's the service on which you registered the listener. So you can just do

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

I can't quite figure out why the compiler can't infer the types from the code you have, but if you properly type the service, providing a parameter for its generic type, then it compiles fine:

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()));
    }

}

There's obviously enough information in your code for the compiler to infer that event is of type WorkerStateEvent , which should allow you to call event.getSource().getException() . I think the type inference just fails for some reason when you use raw types ( Service ) instead of generically-typed objects ( Service<Void> etc).

The signature of setOnFailed is

public final void setOnFailed(EventHandler<WorkerStateEvent> value)

So you need to provide an 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 just retuns a java.util.EventObject which does not have the method getException() that WorkerStateEvent has.

Use generics:

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

Edit:

Compiling the non-generic version with plain javac throws the same error:

src/stackoverflowfx/StackOverflowFX.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/stackoverflowfx/StackOverflowFX.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

So this is not an IDE problem.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM