2010-07-13 128 views
94

這些代碼語句是否相同? 他們之間有什麼區別嗎?try/catch與throws異常

private void calculateArea() throws Exception { 
     ....do something 
    } 

private void calculateArea() { 
     try { 
      ....do something 

     } catch (Exception e) { 
      showException(e); 
     } 
    } 
+2

不是一個真正的答案,但你可能會感興趣的斯內德爾德的文章[例外在雨林](http://nedbatchelder.com/text/exceptions-in-the-rainforest.html),這有助於解釋一種情況,其中一種風格或另一種風格是首選。 – 2010-07-13 21:30:13

+1

而不是在catch中有「showException(e)」,你是問你是否在catch中拋出了e(或者根本沒有try/catch)? – MacGyver 2012-01-22 10:51:15

回答

116

是的,有一個巨大的差異 - 後者燕子異常(顯示它,無可否認),而第一個將讓它傳播。 (我假設showException不會重新拋出它。)

因此,如果您調用第一個方法並且「執行某些操作」失敗,則調用方將必須處理該異常。如果你調用第二種方法,並且「做某事」失敗,那麼調用者將不會看到任何異常......這通常是一件壞事,除非showException已經真正地處理了異常,修復了任何錯誤,並且一般確保calculateArea已達到其目的。

您可以告訴這點,因爲你不能調用的第一個方法沒有任何自己Exception聲明你的方法可能把它扔了。

+10

當你提到「除非真正處理了例外情況」,這是一個很好的觀點。我只是認爲我會補充說,捕獲「異常」本身很少導致智能「處理」實際的異常,這是人們推薦您儘可能捕獲最具體的異常的原因。 – 2010-07-13 21:30:38

+16

+1。因爲Jon Skeet需要更多聲望。哦,答案也很好。 – 2013-05-02 10:37:25

13

是的。聲明throws Exception的版本將需要調用代碼來處理異常,而明確處理它的版本則不會。

即,簡單地說:

performCalculation(); 

與移動的處理異常給調用者的負擔:

try { 
    performCalculation(); 
catch (Exception e) { 
    // handle exception 
} 
11

首先一個throws Exception,所以調用者需要處理Exception。第二個在內部捕獲和處理Exception,所以調用者不必做任何異常處理。

+0

所以簡而言之,我應該總是使用第二個。我對嗎? 第一個實際上是一個在程序的不同點使用的方法。這就是爲什麼我決定彙集指令進一步使用,但做了這些,我現在認識到,T是一個很大的錯誤。 – carlos 2010-07-13 21:20:57

+7

不,這兩種模式都需要。如果你的方法可以處理異常,則使用第二種模式,如果不是,則使用第一種模式來通知呼叫者。 – 2010-07-13 21:23:07

+0

您使用的版本取決於您的要求 - 基本上您需要在什麼級別處理該異常。來電者需要進行相應的編碼。如果調用者正在調用第一個版本,並將方法定義替換爲第二個版本,則調用者代碼將被強制處理該異常,因爲這是一個檢查異常。 – samitgaur 2010-07-13 21:25:03

4

是的,它們之間有很大的區別。在第一個代碼塊中,您將異常傳遞給調用代碼。在第二個代碼塊中,你自己處理它。哪一種方法是正確的,完全取決於你在做什麼。在某些情況下,您希望代碼處理異常(例如,如果沒有找到文件並且想要創建它),但在其他情況下,您希望調用代碼處理異常(找不到文件他們需要指定一個新的或創建它)。

一般來說,您也不希望發現一般異常。相反,您只需要捕獲特定的特定字符,例如FileNotFoundExceptionIOException,因爲它們可能意味着不同的內容。

1

我假設你說的「相同」是指行爲。

1)返回值

2)拋出異常

3)副作用(I:

的功能的行爲可以通過確定。在堆中,文件系統等發生變化)

在這種情況下,第一種方法傳播任何異常,而第二種方法不引發檢查異常,併吞下大多數未經檢查的異常,因此行爲不同。

但是,如果你保證,「做什麼」從來沒有拋出一個異常,那麼行爲將是相同的(儘管編譯器將需要調用者來處理異常,在第一個版本)

--edit -

從API設計的角度來看,這些方法在他們的合同中是完全不同的。另外,不建議拋出類Exception。嘗試拋出更具體的東西,以便調用者更好地處理異常。

3

有一種特殊情況,我們不能使用拋出,我們必須使用try-catch。 有一條規則:「重寫的方法不能拋出除父類正在拋出的東西外的其他異常」。如果有任何額外的異常應該使用try-catch處理。 考慮這個代碼片段。 有一個簡單的基類

package trycatchvsthrows; 

public class Base { 
    public void show() 
    { 
     System.out.println("hello from base"); 
    } 
} 

和它的派生類:

package trycatchvsthrows; 

public class Derived extends Base { 

    @Override 
    public void show() { 
     // TODO Auto-generated method stub 
     super.show(); 

     Thread thread= new Thread(); 
     thread.start(); 
     try { 
      thread.sleep(100); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     // thread.sleep(10); 
     // here we can not use public void show() throws InterruptedException 
     // not allowed 
    } 
} 

當我們調用Thread.sleep()方法,我們不得不使用的try-catch,在這裏我們不能使用:

public void show() throws InterruptedException 

因爲重寫的方法不能拋出額外的異常。

+0

我相信不是每個人都知道這個警告。好指出。 – ivanleoncz 2017-11-25 14:59:21

0

此方法的調用者將需要捕獲此異常或將其聲明爲在其方法簽名中重新生成。

private void calculateArea() throws Exception { 
     // Do something 
    } 

在下面的try-catch塊示例中。這個方法的調用者不必擔心處理異常,因爲它已經被處理了。

private void calculateArea() { 
    try { 
     // Do something 

    } catch (Exception e) { 
     showException(e); 
    } 
} 
0

很多時候你希望調用者處理異常。假設調用者調用一個調用另一個調用另一個方法的方法的方法,而不是讓每個方法處理異常,您可以在調用者處理它。除非你想在這種方法失敗時在其中一種方法中做某件事。

1

如果拋出一個異常,孩子的方法(將覆蓋此)應該處理異常

例如:

class A{ 
public void myMethod() throws Exception{ 
//do something 
} 
} 

A a=new A(); 
try{ 
a.myMethod(); 
}catch Exception(e){ 
//handle the exception 
}