[英]How can i catch Event Dispatch Thread (EDT) exceptions?
我正在使用一個名為MyExceptionHandler
的類來實現Thread.UncaughtExceptionHandler
來處理項目中的正常異常。
據我所知,這個類無法捕獲EDT異常,所以我嘗試在main()
方法中使用它來處理EDT異常:
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
來測試異常處理程序,但它沒有用! 例外通常打印在日志中。
我在這里做錯了嗎?
EDT異常處理程序不使用Thread.UncaughtExceptionHandler
。 相反,它調用具有以下簽名的方法:
public void handle(Throwable thrown);
將它添加到MyExceptionHandler
,它應該工作。
對此的“文檔”可在EventDispatchThread
找到,它是java.awt
的包私有類。 從handleException()
的javadoc引用:
/**
* Handles an exception thrown in the event-dispatch thread.
*
* <p> If the system property "sun.awt.exception.handler" is defined, then
* when this method is invoked it will attempt to do the following:
*
* <ol>
* <li> Load the class named by the value of that property, using the
* current thread's context class loader,
* <li> Instantiate that class using its zero-argument constructor,
* <li> Find the resulting handler object's <tt>public void handle</tt>
* method, which should take a single argument of type
* <tt>Throwable</tt>, and
* <li> Invoke the handler's <tt>handle</tt> method, passing it the
* <tt>thrown</tt> argument that was passed to this method.
* </ol>
*
* If any of the first three steps fail then this method will return
* <tt>false</tt> and all following invocations of this method will return
* <tt>false</tt> immediately. An exception thrown by the handler object's
* <tt>handle</tt> will be caught, and will cause this method to return
* <tt>false</tt>. If the handler's <tt>handle</tt> method is successfully
* invoked, then this method will return <tt>true</tt>. This method will
* never throw any sort of exception.
*
* <p> <i>Note:</i> 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
* <i>will be removed</i> in a future release.
*/
太陽如何期待你發現這一點,我不知道。
這是一個完整的例子,可以捕獲EDT內外的異常:
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捕獲:
總結以上內容......使用較新的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)));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.