2016-10-06 32 views
6

從上java.lang.Exception類的javadoc:Java的檢查異常處理是否被破壞?

經過異常需要在方法或構造方法 擬申報throws子句,如果他們可以通過該方法的執行或 構造函數拋出的方法或構造邊界外傳播。

但考慮下面的代碼:

package other; 

public class CheckedExceptionHandling { 

    private static <E extends Exception> void throwException() throws E { 
     throw (E) new CheckedException2(); // unchecked cast warning 
    } 

    private static void setUncaughtExceptionHandler() { 
     Thread.currentThread().setUncaughtExceptionHandler((t, e) -> { 
      System.out.println("Unhandled exception: " + e.getClass()); // reports CheckedExceptionHandling$CheckedException2 
     }); 
    } 

    public static void main(String[] args) /* no checked exceptions declared! */ { 
     setUncaughtExceptionHandler(); 
     try { 
      CheckedExceptionHandling.<CheckedException1>throwException(); 
     } catch (CheckedException1 e) { 
      System.out.println(e); // never gets here 
     } 
    } 
    // checked exceptions: 
    public static class CheckedException1 extends Exception {} 
    public static class CheckedException2 extends Exception {} 

} 

它編譯提出警告,並在運行時的結果是:

未處理的異常:類other.CheckedExceptionHandling $ CheckedException2

我預計編譯時錯誤unreported exception CheckedException2; must be caught or declared to be thrownincompatible types: CheckedException2 cannot be converted to CheckedException1或至少一個ClassCastException在運行時。
編譯器允許檢查的異常未處理,未聲明並在方法main之外傳播到未捕獲的異常處理程序
爲什麼?我在這裏錯過了什麼嗎?

+0

加一。寫得不錯的問題。 Java異常處理被破壞。最終,你會習慣於那樣,冷靜下來。 – Bathsheba

+1

這裏沒有什麼破碎的。這完全符合規格。 – Tunaki

+2

這看起來很像「偷偷摸摸」。在您選擇的搜索引擎上搜索該詞,例如https://www.reddit.com/r/programming/comments/2x41h4/sneaky_exceptions_in_java/ –

回答

0

問題是編譯器沒有看過去的方法範圍。在throwsException()中,除了「extends Exception」之外,沒有關於E的信息,因此編譯器無法證明該轉換是錯誤的,並且發出警告,而不是錯誤(正如Marko在註釋中已經指出的那樣)。

在main()中,編譯器只看到「throwsException」的簽名,它被定義爲「throws E」,在main()中,E是CheckedException。由於CheckedException被捕獲,所以在這裏一切都很好。

然後,Java在編譯時拋出所有泛型類型信息,所以在字節碼中不會出現強制轉換爲E的類型。因此,運行時也無法檢測到類型錯誤。

這裏打破的不是異常處理,而是類型系統。