2010-12-15 50 views
18

我正在使用一个名为MyExceptionHandler的类来实现Thread.UncaughtExceptionHandler来处理我的项目中的正常异常。如何捕捉事件调度线程(EDT)异常?

据我所知这个类不能赶上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我从一个包文件中像这样的构造加载其标签:

setTitle(bundle.getString("MyJFrame.title")); 

我删除从包文件的密钥MyJFrame.title测试异常处理程序,但它没有工作!例外通常是打印在日志中。

我在这里做错了什么?

+0

可能重复的[如何捕捉Java中的AWT线程异常?](http://stackoverflow.com/questions/95767/how-can-i-catch-awt-thread-exceptions- in-java) – Suma 2015-01-09 10:15:25

回答

29

EDT异常处理程序不使用Thread.UncaughtExceptionHandler。相反,它调用具有以下签名的方法:

public void handle(Throwable thrown); 

加入,为MyExceptionHandler,它应该工作。

此文档在EventDispatchThread中找到,它是java.awt中的包专用类。从javadoc中引述了handleException()有:

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

应该这样做。

+0

@uckelman ...我做了你提到的,但是没有发现异常! ...公共无效句柄(抛出抛出){ \t \t System.out.println(“Exception is Catched”); //是否打印机器人! \t} – Brad 2010-12-15 11:01:54

+0

@Brad:在上面给出的示例中不会运行'handle()',因为EDT上不会出现异常。尝试'JFrame frame = null;'强制执行一个异常。 – uckelman 2010-12-15 11:10:27

+0

@uckelman ...如果我按照你提到的例子,那么异常将由你提到的句柄(...)处理。即使句柄(...)不存在,那么异常将由实施的方法uncaughtException(...)处理,然后不需要处理(...)!但是,完全失败的情况是,如果我初始化一个JFrame,然后打开另一个JFrame,它的标题在我的问题中提到的包文件中错过了。这个异常不是由句柄(...)或ncaughtException(...)处理,而只是打印到日志中。 – Brad 2010-12-15 11:34:15

0

只是一些额外的信息,在许多情况下,即使在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; 
} 

根据这个代码,只有3种方式可抛出不会被EDT线程的UncaughtExceptionHandler的被抓:

  1. 的是Throwable的通过成功的sun.awt.exception.handler处理(类被发现,实例化,并呼吁它的句柄(的Throwable)方法不抛出任何东西)在一个模式对话框
  2. EDT为的Throwable的既不是一个RuntimeExceptionñ或错误