2013-06-04 65 views
2

我對於例外有些疑問。需要說明的例外代碼

誰能告訴我,爲什麼java的犯規讓我們在子類中創建的Checked Exception,同時允許未經檢查的異常在子類中

下面exampple拋出編譯時錯誤,當我使用「拋出IOException異常」,但它不拋當我在子類中使用「拋出ArithmeticException」時出現任何錯誤。我只想知道它背後的真實原因,那麼可以嗎?

這裏是代碼(你會得到編譯時錯誤)

package com.exception.test; 

import java.io.IOException; 

public class Parent { 

    void msg() { 
     System.out.println("Parent..."); 
    } 

    public static void main(String[] args) { 
     Parent parent = new Child(); 
     parent.msg(); 
    } 
} 


class Child extends Parent { 

    void msg() throws IOException { 
     System.out.println("Child..."); 
    } 

} 

//使用unCheckedException

package com.exception.test; 

import java.io.IOException; 

public class Parent { 

    void msg() { 
     System.out.println("Parent..."); 
    } 

    public static void main(String[] args) { 
     Parent parent = new Child(); 
     parent.msg(); 
    } 
} 


class Child extends Parent { 

    void msg() throws ArithmeticException { 
     System.out.println("Child..."); 
    } 

} 
+1

重寫方法有規則。在子類中,在重寫的方法中,你只能拋出超類聲明的異常或超類異常類型的異常。例如,如果超類的方法methodA聲明IOException,則子類的重寫方法可以拋出IOException或例如SocketException(IOException的子類)。總是可以聲明並拋出運行時異常。 – michal

回答

5

如果子類方法聲明可能拋出checked異常的父母沒有,它打破了Liskov substitution principle,這是面向對象編程的一個角落。

考慮這段代碼,與申報Child.msg拋出checked異常:如果你在一個子對象傳遞,因爲檢查異常,現在既沒有被抓到,也沒有拋出

void doMsg(Parent p) { 
    p.msg(); 
} 

程序語義破解:在異常不再被「檢查」。

由於未檢查的異常可以在任何地方引發,因此聲明拋出異常除了文檔之外沒有其他用途。因此它可以安全地被允許。

+0

如果你不介意,你可以用一個簡單的例子來解釋我。爲什麼java正是這樣的規則? – Irwin

+0

你問「爲什麼java遵循Liskov替代原則?」或者「爲什麼聲明在子類中拋出檢查過的異常會打破它呢?」 – Joni

0

您父類中的msg()方法可以拋出任何它喜歡的未經檢查的異常。因此,如果你明確地聲明你的孩子拋出了一個未經檢查的異常,那麼你實際上並沒有改變合同。你的孩子的方法可能ArithmeticException,但也可能你的父母的方法。

0

不幸的是,你已經遇到另一個錯誤稱爲檢查異常的錯誤。您收到的錯誤是所有Java專業人員面臨的實際問題:您正在實現一種方法,其中的某些代碼恰巧會拋出未由超類方法聲明的檢查異常。已聲明的已檢查異常是Java方法簽名的一部分;您可以減少子類中的列表,但不能擴展它。

如果這是更多的只是一個「爲什麼」的問題,你需要一個解決辦法,標準成語是

try { 
    ...code that throws the checked exception... 
} catch (TheCheckedException e) { throw new RuntimeException(e); } 

這就是所謂的例外包裝。如果你有超過一個或兩個未申報檢查的異常,也可以使用相反的成語,確保所有聲明的異常透明地傳播和所有未申報的人得到包裹:

try { 
    ...code that throws various checked exceptions... 
} 
catch (DeclaredEx1 | DeclaredEx2 | RuntimeException e) { throw e;} 
catch (Exception e) { throw new RuntimeException(e); } 
0

經過檢查的異常可以在覆蓋範圍縮小,但不能擴大。未經檢查的異常不需要被覆蓋的方法

From the java specs

評爲throws子句中選中的異常類被抓是 方法或 構造函數的實現者和用戶之間的合同的一部分。重寫方法的throws子句可能沒有指定 ,該方法將導致拋出任何經檢查的異常,其中 重寫的方法不允許通過其拋出子句拋出 拋出。