問題: 我在我的應用程序中調用了外部方法并且想捕獲它可能拋出的異常。我能捕獲java.lang.Exception嗎?
答案: 通過一個給定的方法去處理所有運行時和檢測異常對于預防外部錯誤是不充分的。
你可以去讀目前 JavaWorld文章 – “Java Tip 134: When Catching Exception, Don’t Cast Your Net Too Wide”。這篇文章警告了捕獲java.lang.Exception和java.lang.Throable是不好的。捕獲你能指定的異常對于代碼的可維護性是十分重要的。然而這個規則依賴于特殊的環境。如果你不打算你的程序崩潰并且保留你的數據結構的安全異常,那么你必須捕獲被拋出的真正的異常。
舉個例子,想象你有一個加載了這個接口的服務器應用:
public interface IFoo { /** * This method can't throw any checked exceptions...or can it? */ void bar (); } // End of interface
對于給出參數的理由是讓我們通知你這樣的服務在什么地方,并且不同的IFoo實現能夠從外部資源加載上。你寫如下代碼:
try { IFoo foo = ... // get an IFoo implementation foo.bar (); } catch (RuntimeException ioe) { // Handle 'ioe' ... } catch (Error e) { // Handle or re-throw 'e' ... }
并且你在這個里處理了所有可能的異常。你不需要在這里加上任何捕獲java.io.IOException的異常,因為IFoo實現沒有從IFoo.bar()中拋出它,對嗎?(事實上,如果你加上了捕獲java.io.IOException異常塊,編譯器可能會把它作為不可到達的異常而丟棄)
錯誤。在我寫的EvilFoo類中bar()方法證明了將拋出你傳遞給類構造器的任何異常:
public void bar () { EvilThrow.throwThrowable (m_throwthis); }
運行Main方法:
public class Main { public static void main (final String[] args) { // This try/catch block appears to intercept all exceptions that // IFoo.bar() can throw; however, this is not true try { IFoo foo = new EvilFoo (new java.io.IOException ("SURPRISE!")); foo.bar (); } catch (RuntimeException ioe) { // Ignore ioe } catch (Error e) { // Ignore e } } } // End of class
你將看到從bar()方法拋出的java.io.IOException異常實例并且沒有任何捕獲塊:
>java -cp classes Main Exception in thread "main" java.io.IOException: SURPRISE! at Main.main(Main.java:23)
在這里發生了什么?
主要的觀察是通常針對檢測異常的Java規則僅僅在編譯的時候被執行。在運行的時候,一個JVM不能保證被一個方法拋出的異常是否和在這個方法中聲明的拋出異常相匹配。因為調用方法的職責是捕獲和處理所有從調用方法拋出的異常。任何沒有被調用方法聲明的異常將不予理睬并且拒絕調用棧。
|