2010-12-15 46 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ñ或錯誤