简体   繁体   English

Java FX 应用程序中未捕获的异常处理程序将 RuntimeExceptions 捕获为 NullPointerExceptions 的问题

[英]Issue with catching RuntimeExceptions as NullPointerExceptions by an uncaught exception handler in Java FX applications

I read this post JavaFx 8 global exception handling and tried to handle uncaught exceptions in my application.我读了这篇文章JavaFx 8 global exception handling并尝试在我的应用程序中处理未捕获的异常。 It works fine as described in the post.如帖子中所述,它工作正常。 But when I added a statement which caused a NullPointerException the UncaughtExceptionHandler did not catch this exception.但是当我添加一个导致 NullPointerException 的语句时,UncaughtExceptionHandler 没有捕获到这个异常。 Why?为什么? Is there another thread handling this exception?是否有另一个线程处理此异常? Or do I have to set the DefaultUncaughtExceptionHandler?还是我必须设置 DefaultUncaughtExceptionHandler? I read JavaDocs:我读了JavaDocs:

Uncaught exception handling is controlled first by the thread, then by the thread's ThreadGroup object and finally by the default uncaught exception handler.未捕获的异常处理首先由线程控制,然后由线程的 ThreadGroup object 控制,最后由默认的未捕获异常处理程序控制。 If the thread does not have an explicit uncaught exception handler set, and the thread's thread group (including parent thread groups) does not specialize its uncaughtException method, then the default handler's uncaughtException method will be invoked.如果线程没有明确的未捕获异常处理程序集,并且线程的线程组(包括父线程组)没有专门化其 uncaughtException 方法,则将调用默认处理程序的 uncaughtException 方法。

I have no idea how to get the solution which handles all uncaught exceptions.我不知道如何获得处理所有未捕获异常的解决方案。 Can you help?你能帮我吗? Thanks for your support!!谢谢你的支持!!

This is the code:这是代码:

package TestSimpleDialog;

public class Main extends Application {
    private final Logger logger = Logger.getLogger(this.getClass().getName());
    private MyHandler myHandler = new MyHandler();
    @Override
    public void init() {
    // Thread.currentThread is the FX-Launcher thread:
    Thread.currentThread().setUncaughtExceptionHandler(myHandler);
    System.out.println(Thread.currentThread().getUncaughtExceptionHandler());
    try {
        logger.addHandler(new FileHandler("java.myLOG"));
    }
    catch (IOException e) {
        throw new IllegalStateException("IOException when adding File Handler");
    }
    }
    @Override
    public void start(Stage primaryStage) {
    logger.info("Test Application started");
    // Thread.currentThread() is the FX-Application thread:
    Thread.currentThread().setUncaughtExceptionHandler(myHandler);
    // If this thread has not had an uncaught exception handler explicitly set then this thread's ThreadGroup object
    // is returned, unless this thread has terminated, in which case null is returned.
    System.out.println(Thread.currentThread().getUncaughtExceptionHandler());

    //        try {
    //            URI uriTest = new URI(null);
    //        } catch (URISyntaxException e) {
    //            throw new IllegalStateException("URISyntaxException by testing");
    //        }

    StackPane root = new StackPane();
    Button button = new Button("Throw exception");
    button.setOnAction(event -> {
        throw new RuntimeException("** T E S T **") ;
    });
    root.getChildren().add(button);
    Scene scene = new Scene(root, 150, 60);
    primaryStage.setScene(scene);
    primaryStage.show();
    }

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

    class MyHandler implements Thread.UncaughtExceptionHandler{
    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        System.out.println("MyHandler caught exception: "+throwable.getMessage());
        logger.log(Level.SEVERE, "**TEST** threw an uncaught exception", throwable);
    }
    }
}

When I push the button, I have got this output on the console:当我按下按钮时,我在控制台上得到了这个 output:

TestSimpleDialog.Main$MyHandler@49285759
Aug. 08, 2020 5:55:33 NACHM. TestSimpleDialog.Main start
INFORMATION: Test Application started
TestSimpleDialog.Main$MyHandler@49285759
MyHandler caught exception: ** T E S T **
Aug. 08, 2020 5:55:51 NACHM. TestSimpleDialog.Main$MyHandler uncaughtException
SCHWERWIEGEND: **TEST** threw an uncaught exception
java.lang.RuntimeException: ** T E S T **
    at TestSimpleDialog.Main.lambda$start$0(Main.java:47)
    at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at javafx.base/com.sun.javafx.event.BasicEventDispatcher............

But when I activated this statement to get a NullPointerException但是当我激活这个语句以获得 NullPointerException

try {
    URI uriTest = new URI(null);
} catch (URISyntaxException e) {
    throw new IllegalStateException("URISyntaxException by testing");
}

I could see on the console that the exception was not caught because of missing the statement "MyHandler caught exception: " the class MyHandler prints on Sysout.我可以在控制台上看到异常没有被捕获,因为缺少语句“MyHandler 捕获异常:” class MyHandler 打印在 Sysout 上。 Furthermore nothing is written on the logging file.此外,日志文件上没有写入任何内容。

TestSimpleDialog.Main$MyHandler@22b2aa29
TestSimpleDialog.Main$MyHandler@22b2aa29
Aug. 08, 2020 6:16:51 NACHM. TestSimpleDialog.Main start
INFORMATION: Test Application started
Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException
    at java.base/java.net.URI$Parser.parse(URI.java:3104)
    at java.base/java.net.URI.<init>(URI.java:600)
    at TestSimpleDialog.Main.start(Main.java:41)
    at javafx.graphics/com.sun.javafx.application.............

Don't have an answer to how - just a tentative explanation to the why (looks like the first thought in my comments wasn't far off;)没有答案 - 只是对原因的初步解释(看起来我评论中的第一个想法并不遥远;)

At its base is the fact that the Application is instantiated via reflection: whatever exceptions happen in init/start bubble up as errors in instantiation, namely as InvocationTargetException.它的基础是应用程序是通过反射实例化的事实:无论在 init/start 中发生的任何异常都会作为实例化中的错误冒泡,即作为 InvocationTargetException。 And these are indeed handled by LauncherImpl.launchApplicationWithArgs by.. ex.printStackTrace这些确实由LauncherImpl.launchApplicationWithArgs由... ex.printStackTrace处理

public static void launchApplicationWithArgs(final ModuleAccess mainModule,
        final String mainClassName,
        final String preloaderClassName, String[] args) {

  // invoke, handle exception, line 472
  ...
    } catch (InvocationTargetException ex) {
        ex.printStackTrace();
        abort(null, "Exception running application %1$s", tempAppClass.getName());
        return;
    }

Don't see any way to intercept that (which might be a bug.. or not).看不到任何拦截它的方法(这可能是一个错误..或不是)。

Edit编辑

To achieve logging (beyond printing to the error output) of errors coalesced into InvocationTargetException, an option might be to wrap the workload of the init/start method into a try.. catch... block and manually invoke the handler, something like为了实现合并到 InvocationTargetException 的错误的日志记录(除了打印到错误输出),一个选项可能是将 init/start 方法的工作负载包装到try..catch...块中并手动调用处理程序,例如

@Override
public void init() throws Exception {
    try {
        // do stuff that might be throwing
        throw new ArithmeticException("am I caught?");
    } catch (Exception ex) {
        // invoke the handler and re-throw
        myHandler.uncaughtException(Thread.currentThread(), ex);
        throw(ex);
    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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