如何捕获事件调度线程(EDT)exception?
我正在使用一个名为MyExceptionHandler
的类来实现Thread.UncaughtExceptionHandler
来处理项目中的正常exception。
据我所知,这个类无法捕获EDTexception,所以我尝试在main()
方法中使用它来处理EDTexception:
public static void main( final String[] args ) { Thread.setDefaultUncaughtExceptionHandler( new MyExceptionHandler() ); // Handle normal exceptions System.setProperty( "sun.awt.exception.handler",MyExceptionHandler.class.getName()); // Handle EDT exceptions SwingUtilities.invokeLater(new Runnable() { // Execute some code in the EDT. public void run() { JFrame myFrame = new JFrame(); myFrame.setVisible( true ); } }); }
但直到现在它还没有用。 例如,在初始化JFrame时,我从构造函数中的bundle文件加载其标签,如下所示:
setTitle( bundle.getString( "MyJFrame.title" ) );
我从包文件中删除了密钥MyJFrame.title
来测试exception处理程序,但它没有用! 例外通常打印在日志中。
我在这里做错了吗?
EDTexception处理程序不使用Thread.UncaughtExceptionHandler
。 相反,它调用具有以下签名的方法:
public void handle(Throwable thrown);
将它添加到MyExceptionHandler
,它应该工作。
对此的“文档”可在EventDispatchThread
找到,它是java.awt
的包私有类。 从handleException()
的javadoc引用:
/** * Handles an exception thrown in the event-dispatch thread. * * If the system property "sun.awt.exception.handler" is defined, then * when this method is invoked it will attempt to do the following: * *
* - Load the class named by the value of that property, using the * current thread's context class loader, *
- Instantiate that class using its zero-argument constructor, *
- Find the resulting handler object's public void handle * method, which should take a single argument of type * Throwable, and *
- Invoke the handler's handle method, passing it the * thrown argument that was passed to this method. *
* * If any of the first three steps fail then this method will return * false and all following invocations of this method will return * false immediately. An exception thrown by the handler object's * handle will be caught, and will cause this method to return * false. If the handler's handle method is successfully * invoked, then this method will return true. This method will * never throw any sort of exception. * * Note: This method is a temporary hack to work around the * absence of a real API that provides the ability to replace the * event-dispatch thread. The magic "sun.awt.exception.handler" property * will be removed in a future release. */
太阳如何期待你发现这一点,我不知道。
这是一个完整的示例,可以捕获EDT内外的exception:
import javax.swing.SwingUtilities; public class Test { public static class ExceptionHandler implements Thread.UncaughtExceptionHandler { public void handle(Throwable thrown) { // for EDT exceptions handleException(Thread.currentThread().getName(), thrown); } public void uncaughtException(Thread thread, Throwable thrown) { // for other uncaught exceptions handleException(thread.getName(), thrown); } protected void handleException(String tname, Throwable thrown) { System.err.println("Exception on " + tname); thrown.printStackTrace(); } } public static void main(String[] args) { Thread.setDefaultUncaughtExceptionHandler(new ExceptionHandler()); System.setProperty("sun.awt.exception.handler", ExceptionHandler.class.getName()); // cause an exception on the EDT SwingUtilities.invokeLater(new Runnable() { public void run() { ((Object) null).toString(); } }); // cause an exception off the EDT ((Object) null).toString(); } }
应该这样做。
仅仅为了一些额外的信息,在很多情况下,即使在1.5和1.6中,Throwables也会被EDT的UncaughtExceptionHandler捕获。 查看1.5.0_22中EventDispatchThread的源代码:
private void processException(Throwable e, boolean isModal) { if (!handleException(e)) { // See bug ID 4499199. // If we are in a modal dialog, we cannot throw // an exception for the ThreadGroup to handle (as added // in RFE 4063022). If we did, the message pump of // the modal dialog would be interrupted. // We instead choose to handle the exception ourselves. // It may be useful to add either a runtime flag or API // later if someone would like to instead dispose the // dialog and allow the thread group to handle it. if (isModal) { System.err.println( "Exception occurred during event dispatching:"); e.printStackTrace(); } else if (e instanceof RuntimeException) { throw (RuntimeException)e; } else if (e instanceof Error) { throw (Error)e; } } } private boolean handleException(Throwable thrown) { try { if (handlerClassName == NO_HANDLER) { return false; /* Already tried, and failed */ } /* Look up the class name */ if (handlerClassName == null) { handlerClassName = ((String) AccessController.doPrivileged( new GetPropertyAction(handlerPropName))); if (handlerClassName == null) { handlerClassName = NO_HANDLER; /* Do not try this again */ return false; } } /* Load the class, instantiate it, and find its handle method */ Method m; Object h; try { ClassLoader cl = Thread.currentThread().getContextClassLoader(); Class c = Class.forName(handlerClassName, true, cl); m = c.getMethod("handle", new Class[] { Throwable.class }); h = c.newInstance(); } catch (Throwable x) { handlerClassName = NO_HANDLER; /* Do not try this again */ return false; } /* Finally, invoke the handler */ m.invoke(h, new Object[] { thrown }); } catch (Throwable x) { return false; } return true; }
根据这段代码,EDT Thread的UncaughtExceptionHandler只有3种方法不会捕获Throwable:
- Throwable由sun.awt.exception.handler成功处理(找到类,实例化并调用其句柄(Throwable)方法而不抛出任何东西)
- EDT处于modal dialog中
- Throwable既不是RuntimeException也不是Error
总结以上内容……使用较新的Java,您可以这样做:
// Log exceptions thrown on the event dispatcher thread SwingUtilities.invokeLater(() -> Thread.currentThread().setUncaughtExceptionHandler((thread, t) -> this.log.error("exception in event dispatcher thread", t)));
- Java Arraylist得到了java.lang.IndexOutOfBoundsException?
- Netbeans FileReader FileNotFound文件在文件夹中时出现exception?
- 如何从容器管理的事务提交中捕获exception?
- Java堆内存错误
- 如何在Swing中捕获此exception?
- java – 在重写方法中检查’throws’的exception
- android.view.WindowManager $ BadTokenException列表视图设置文本然后焦点
- httpclientexception“org.apache.http.conn.ConnectionPoolTimeoutException:超时等待连接”
- 带有监听器的JavaFX Textfield给出:“java.lang.IllegalArgumentException:start必须<= the end”