【问题标题】:Issue with catching RuntimeExceptions as NullPointerExceptions by an uncaught exception handler in Java FX applicationsJava FX 应用程序中未捕获的异常处理程序将 RuntimeExceptions 捕获为 NullPointerExceptions 的问题
【发布时间】:2020-11-28 17:28:45
【问题描述】:

我阅读了这篇文章JavaFx 8 global exception handling 并尝试在我的应用程序中处理未捕获的异常。如帖子中所述,它工作正常。但是当我添加一个导致 NullPointerException 的语句时,UncaughtExceptionHandler 没有捕获到这个异常。为什么 ?是否有另一个线程处理此异常?还是我必须设置 DefaultUncaughtExceptionHandler?我读了JavaDocs:

未捕获的异常处理首先由线程控制,然后由线程的 ThreadGroup 对象控制,最后由默认的未捕获异常处理程序控制。如果线程没有显式设置未捕获异常处理程序,并且线程的线程组(包括父线程组)没有专门化其 uncaughtException 方法,则将调用默认处理程序的 uncaughtException 方法。

我不知道如何获得处理所有未捕获异常的解决方案。你能帮我吗?感谢您的支持!!

这是代码:

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

当我按下按钮时,我在控制台上得到了这个输出:

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............

但是当我激活这个语句得到一个 NullPointerException 时

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

我可以在控制台上看到异常没有被捕获,因为缺少语句“MyHandler 捕获异常:”类 MyHandler 打印在 Sysout 上。此外,日志文件上没有写入任何内容。

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.............

【问题讨论】:

  • hmm .. 不完全确定:但看起来启动器处理所有异常(通过打印出堆栈跟踪)。如果您在普通主程序(不是应用程序)中执行相同操作,则会调用处理程序。
  • 不,通过打印堆栈跟踪 - 它将所有内容包装到 RuntimeException 中并抛出它;)
  • 所以回到第 0 步:你想达到什么目标?你可以在启动时设置一个全局的 uncaughtExceptionHandler ..
  • 不,行不通.. 想出来的想法(而且在中欧太热,无法真正考虑清楚,抱歉;)

标签: javafx runtimeexception uncaughtexceptionhandler threadgroup


【解决方案1】:

没有如何的答案 - 只是对为什么的试探性解释(看起来我的 cmets 的第一个想法并不遥远;)

应用程序是通过反射实例化的事实:无论在 init/start 中发生的任何异常都会作为实例化中的错误冒泡,即 InvocationTargetException。而这些确实是由LauncherImpl.launchApplicationWithArgs by .. 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;
    }

看不到任何拦截它的方法(这可能是一个错误..或不是)。

编辑

为了实现对合并到 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);
    }

}

【讨论】:

  • 这是否意味着没有任何内容写入日志文件,而只是写入错误打印流?方法 abort 是怎么回事?
  • 好吧,如果处理程序无法捕获错误,那么捕获方法中的记录器也不是;) 你说的 abort 是什么意思?
  • 反正还是不太明白自己想要达到什么目的?如果它只是您感兴趣的日志记录,则可能足以将 start/int 中的所有内容包装到 try/catch 并登录到 catch 块?
  • 是的,我对日志记录很感兴趣。同时我做了包装成 try/catch 块。但是当有一个 java.lang.ArithmeticException: / 为零时,例如它被 launchApplicationWithArgs 捕获。这意味着写入错误打印流。就是这样,没有抛出异常,因此日志文件中没有条目。顺便说一句,谢谢你的帮助!
  • 我刚刚注意到您已经编辑了答案。现在,我明白了将所有内容包装在 start/ini 中的意思。因此我改变了我的代码。现在它对我来说很好用。
猜你喜欢
  • 1970-01-01
  • 2013-10-25
  • 2014-09-02
  • 1970-01-01
  • 1970-01-01
  • 2014-03-22
  • 2018-05-30
  • 1970-01-01
  • 2018-06-14
相关资源
最近更新 更多