2013-03-04 84 views
67

我擔心這是一個運行時異常,所以應該謹慎使用它。
標準使用案例:何時應拋出IllegalArgumentException?

void setPercentage(int pct) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("bad percent"); 
    } 
} 

但是,這似乎將迫使下面的設計:

public void computeScore() throws MyPackageException { 
     try { 
      setPercentage(userInputPercent); 
     } 
     catch(IllegalArgumentException exc){ 
      throw new MyPackageException(exc); 
     } 
} 

爲了得到它重新成爲一個檢查異常。

好的,但讓我們一起去。如果你輸入錯誤,你會得到一個運行時錯誤。所以,首先這實際上是一個相當困難的政策來實現均勻的,因爲你可以有做的很相反的轉換:

public void scanEmail(String emailStr, InputStream mime) { 
    try { 
     EmailAddress parsedAddress = EmailUtil.parse(emailStr); 
    } 
    catch(ParseException exc){ 
     throw new IllegalArgumentException("bad email", exc); 
    } 
} 

更糟糕的是 - 當檢查0 <= pct && pct <= 100客戶端代碼可望靜態做的,事實並非如此以獲取更高級的數據,例如電子郵件地址,或者更糟糕的是,必須對數據庫進行檢查,因此通常客戶端代碼無法預先驗證。

所以基本上我所說的是我沒有看到使用IllegalArgumentException的有意義的一致性政策。它似乎不應該被使用,我們應該堅持我們自己的檢查異常。什麼是好的用例來拋出這個?

回答

51

的API文檔的IllegalArgumentException的:

拋出,表明一個方法傳遞了一個不合法或不正確的說法。

通過觀察how it is used in the jdk libraries,我會說:

  • 這似乎是一種防禦措施抱怨顯然是錯誤的輸入之前的輸入可以進入作品,並導致一些中途失敗通過一個無意義的錯誤消息。

  • 它用於那些拋出一個檢查異常太煩人的情況(雖然它在java.lang.reflect代碼中出現,在這種情況下,關於checked-exception-throwing的荒謬級別的關注並不明顯)。

我會用拋出:IllegalArgumentException做最後一搏的防守參數,檢查常用工具(儘量保持與JDK用法一致),其中期望是一個不好的說法是一個程序員的錯誤,類似於NPE。我不會用它來實現業務代碼中的驗證。我當然不會將它用於電子郵件示例。

+5

我認爲這個建議「期望是一個糟糕的論點是一個程序員錯誤」與我所見過的使用方式最爲一致,所以接受了這個答案。 – djechlin 2013-03-07 03:22:27

9

「謹慎地」拋出運行時異常並不是一個很好的策略 - 有效的Java建議您在合理預期調用者可以使用時檢查異常。 (程序員錯誤是一個具體的例子:如果一個特定的案例表明程序員錯誤,那麼你應該拋出一個未經檢查的異常;你希望程序員有一個邏輯問題發生的地方的堆棧跟蹤,而不是試圖自己處理它。)

如果沒有恢復的希望,那麼可以隨意使用未經檢查的異常;捕捉它們沒有意義,所以這非常好。

雖然這不是100%從你的例子中清楚的例子,但是這個例子在你的代碼中。

+0

我認爲「合理的預期恢復」是杞人憂天。任何操作'foo(data)'都可能作爲'for data(list data)foo(data)'的一部分發生;'即使某些數據格式錯誤,調用者可能希望儘可能多地成功。如果我的應用程序失敗意味着交易不會經歷那可能更好,如果這意味着核冷卻脫機是不好的,那麼也包括程序錯誤。 – djechlin 2013-03-04 19:24:57

+0

'StackOverflowError'和這樣的情況下,調用者無法合理預期從中恢復。但它聽起來像應該檢查任何數據或應用程序邏輯級別的情況。這意味着你的空指針檢查! – djechlin 2013-03-04 19:25:54

+3

在覈冷卻應用中,我寧願在測試中失敗,也不願讓程序員認爲不可能不被忽視的情況。 – 2013-03-04 20:09:00

4

在Oracle官方指定教程,它指出:

如果客戶可以合理預期從異常恢復, 使它成爲一個檢查異常。如果客戶端無法執行任何操作以從異常中恢復 ,請將其設置爲未檢查的異常。

如果我有使用JDBC數據庫的應用程序進行交互,而我有需要的參數作爲int itemdouble price的方法。相應項目的price從數據庫表中讀取。我只需將購買的item總數與price值相乘並返回結果。儘管我總是在我的最後(申請結束)確定表格中的價格字段值永遠不會爲負數。但是如果價格值出來怎麼辦?否定?它表明數據庫方面存在嚴重問題。也許是運營商輸入錯誤的價格。這是調用該方法的應用程序的其他部分無法預料並且無法從中恢復的問題。它在您的數據庫中是一個BUG。所以,IllegalArguementException()應該拋出在這種情況下,將聲明the price can't be negative
我希望我已經表達了我的觀點清楚..

17

當談到「糟糕的輸入」時,你應該考慮輸入來自哪裏。

如果用戶或其他外部系統輸入的輸入是不受控制的,那麼您應該預期輸入無效,並始終對其進行驗證。在這種情況下拋出一個檢查的異常是完全可以的。您的應用程序應通過向用戶提供錯誤消息來從此異常中「恢復」。

如果輸入來自您自己的系統,例如你的數據庫或應用程序的其他部分,你應該可以依賴它來證明它是有效的(它應該在它到達之前進行驗證)。在這種情況下,最好拋出一個未經檢查的異常,如IllegalArgumentException,這個異常不應該被捕獲(通常你​​不應該捕獲未經檢查的異常)。這是一個程序員的錯誤,無效的值首先到達那裏;)您需要修復它。

+1

爲什麼「你永遠不應該捕捉不受限制的例外」? – 2015-12-14 17:19:37

+5

因爲一個未經檢查的異常是由於編程錯誤而引發的。拋出這種異常的方法的調用者不能合理地期望從其中恢復,因此通常無法捕捉到它們。 – Tom 2015-12-15 20:53:53

+0

'因爲一個未經檢查的異常是由於編程錯誤而被拋出的'幫助我清除了很多東西在我腦海中,謝謝:) – svarog 2017-06-27 12:25:50

5

任何API應該檢查任何公開的方法的每一個參數的有效性執行前:

void setPercentage(int pct, AnObject object) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("pct has an invalid value"); 
    } 
    if (object == null) { 
     throw new IllegalArgumentException("object is null"); 
    } 
} 

他們是時代錯誤的99.9%,在應用,因爲它是要求不可能的操作,以便在最終它們是應該使應用程序崩潰的錯誤(所以它是不可恢復的錯誤)。

在這種情況下,在快速失敗的方法之後,應該讓應用程序完成以避免損壞應用程序狀態。

+0

相反,如果一個API客戶端給我一個不好的輸入,我應該*不*會崩潰我的整個API服務器。 – djechlin 2017-09-29 15:52:22

+0

當然,它不應該崩潰你的API服務器,但返回一個異常給調用者這應該不會崩潰任何東西,但客戶端。 – 2017-10-02 07:27:57

+0

你在評論中寫的不是你在答案中寫的。 – djechlin 2017-10-02 14:14:54

相關問題