2013-10-05 21 views
23

我想清除中的方法簽名中的拋出拋出Java中的語句。 拋出在方法簽名如下:方法簽名中的拋出和Java中的拋出語句之間的區別

public void aMethod() throws IOException{ 
    FileReader f = new FileReader("notExist.txt"); 
} 

throw語句是如下:

public void bMethod() { 
    throw new IOException(); 
} 

從我的理解,在方法簽名throws是,該方法可能會拋出這樣的異常的通知。語句是在相應的情況下實際拋出創建的對象的語句。 從這個意義上說,在方法簽名中拋出應該總是出現,如果在方法中存在拋出語句。

但是,下面的代碼似乎並沒有這樣做。代碼來自庫。我的問題是爲什麼它發生?我是否理解錯誤的概念?

這段代碼是java.util.linkedList的副本。 @author對答案喬希布洛赫

/** 
* Returns the first element in this list. 
* 
* @return the first element in this list 
* @throws NoSuchElementException if this list is empty 
*/ 
public E getFirst() { 
    final Node<E> f = first; 
    if (f == null) 
     throw new NoSuchElementException(); 
    return f.item; 
} 

更新:

更新1:是上面的代碼相同,以下?

// as far as I know, it is the same as without throws 
public E getFirst() throws NoSuchElementException { 
    final Node<E> f = first; 
    if (f == null) 
     throw new NoSuchElementException(); 
    return f.item; 
} 

更新2:對於檢查的異常。我需要在簽名中「扔」嗎?是。

// has to throw checked exception otherwise compile error 
public String abc() throws IOException{ 
    throw new IOException(); 
} 
+2

只是一個小小的更正:'throw'語句不會創建可拋出的對象;它只是拋出一個已經創建的對象。這是創建對象的'new'關鍵字。把'throw new MyException()'看作'throw(new MyException())'。你也可以有'MyException e = new MyException();扔e'。看到不同? 'throw'拋出,'new'創建一個實例。 –

回答

23

你幾乎是對的。除了我會提到的一件事。

拋出與方法API的名稱和參數一樣多。客戶知道他們是否調用該方法,他們需要處理該異常 - 只需簡單地拋出它或捕獲它並處理它(這實際上可能引發包含原始異常的另一個異常)。 在編譯時拋出

throw是讓運行時知道發生了什麼壞事的實際行爲 - 我們擔心的特殊情況事實上已經發生。所以它需要在運行時處理。

但是當您說「如果方法中存在throw語句時,方法簽名中的拋出應始終顯示」。這往往是事實,但並非總是如此。我也可以調用另一個在我的方法中拋出異常的方法,如果我沒有捕獲它,我的方法需要拋出它。在這種情況下,我沒有明確拋出同樣的例外。

的最後一點是,你只需要在聲明異常拋出當異常是檢查例外 - 這意味着它是從RuntimeException的異常類層次結構的另一側。常見的檢查異常是IOException和SQLException。如果您自己不處理,則必須在方法簽名的引發部分中列出檢查的異常。任何繼承RuntimeException的東西 - 就像你的例子中的NoSuchElementException,也是討厭的NullPointerException - 是一個未經檢查的異常,不必被捕獲或拋出或任何東西。

通常情況下,您使用檢查異常的可恢復問題(客戶端知道會發生什麼情況,可以正常處理問題並繼續前進)和未檢查異常的災難性問題(如無法連接到數據庫)。

如果你可以通過所有AOP的東西,this是一個很好的討論如何有效地使用checked和unchecked例外。

+0

如果我們沒有處理它們,在'throws'中列出檢查的異常有什麼用處?他們是否被自動抓到? 而且在NullPointerException的情況下,爲什麼不必被捕獲?我可以在運行時得到它,我們可以捕獲它並給出一個簡單的錯誤消息? – Diffy

+0

NullPointerException將暗示代碼中存在錯誤。你絕不應該讓它們理想地發生。 – Kkov

2

RuntimeException小號不要在try-catch塊進行處理,使他們不因爲拋出NoSuchElementExceptionRuntimeException因爲它擴展它已經被宣佈。

+0

那麼如何處理RunTimeException。我們不應該處理NullPointerException和RunTimeException? – Diffy

+1

@Diffy你可以用try-catch來處理這類異常,但最好的辦法是讓它們停止應用程序,因爲它們很可能代表需要糾正的代碼中的錯誤。 – Pshemo

2

throw方法簽名中的屬性,就像你正確猜測的那樣,是編譯器提示該方法引發了一個必須被調用者捕獲的異常。這種例外情況,即檢查異常是呼叫者總是再次收到或發送給其主叫方的東西。這是編譯器級別的東西,簽名指定了該方法能拋出哪個異常:這會強制調用try-catch或在調用方中重新分派,並在方法內的某處放置throw語句,這是開發人員設置的一個約束,用於指定有關方法的行爲。

在另一方面其他例外,即選中運行時異常,(NoSucheElementException就是一個例子),是你不會被強迫指定監守他們來自不同的情況下會出現異常。

概念不同的是,經過檢查的異常通常是用來警告應以某種方式處理異常情況(想想IOException)的開發,同時選中是真正的錯誤(如在你的榜樣NoSuchElementExceptionNullPointerException或類似)

2

Vidya爲您的問題提供了很好的答案。

最重要的詞是「最後一點是,你只需要在異常是一個checked異常申報的例外拋出」

只是爲了顯示你的示例代碼這是什麼意思。想象一下,我們想要使用FileOutputStream來傳遞一些數據。該功能應該是這樣的:

public void saveSomeData() throws IOException { 
    FileInputStream in = null; 
    FileOutputStream out = null; 

    try { 
    in = new FileInputStream("input.txt"); 
    out = new FileOutputStream("output.txt"); 
    int c; 

    while ((c = out.read() != -1) { 
     in.write(c); 
    } 
    } catch (Exception e) { 
    e.printStackTrace(); 
    } finally { 
    // Close in 
    if (in != null) { 
     in.close(); // <-- If something bad happens here it will cause runtime error! 
    } 
    // Close out 
    ... 
    } 
} 

現在想象一下,如果你不能提供拋出IOException異常和不測最後{}語句中 - 這將導致錯誤。

相關問題