針對檢查異常的狀況

多年以來,我一直沒法得到如下問題的正確答案:爲何某些開發人員如此反對檢查異常? 我進行了無數次對話,閱讀了博客上的東西,閱讀了布魯斯·埃克爾(Bruce Eckel)所說的話(我看到的第一個反對他們的人)。 程序員

我目前正在編寫一些新代碼,並不是常注意我如何處理異常。 我正在嘗試查看「咱們不喜歡檢查的異常」人羣的觀點,但我仍然看不到它。 數據庫

個人每一次對話都以相同的問題爲結尾而結束...讓我進行設置: 編程

整體而言(根據Java的設計方式), 數組

  • Error是針對不該該被抓到的東西(VM有花生過敏症,有人在上面撒了一罐花生)
  • RuntimeException適用於程序員作錯的事情(程序員走出了數組的結尾)
  • ExceptionRuntimeException除外)適用於程序員沒法控制的事情(寫入文件系統時磁盤已滿,已達到該進程的文件句柄限制,而且您沒法打開其餘文件)
  • Throwable只是全部異常類型的父級。

我聽到的一個常見論點是,若是發生異常,那麼開發人員要作的就是退出程序。 架構

我聽到的另外一個常見論點是,檢查異常會使重構代碼更加困難。 框架

對於「我要作的就是退出」參數,我說即便您要退出,也須要顯示一條合理的錯誤消息。 若是您只是在處理錯誤,那麼當程序退出時若是沒有明確說明緣由的話,您的用戶將不會過度高興。 函數

對於「它很難重構」人羣,這代表未選擇適當的抽象級別。 與其聲明一個方法拋出IOException而不是將IOException轉換爲更適合發生的異常。 測試

對於將Main與catch(Exception) (或在某些狀況下, catch(Throwable)進行包裝以確保程序能夠正常退出,我沒有任何問題-但我老是捕獲所需的特定異常。至少顯示適當的錯誤消息。 spa

人們從不回覆的問題是: 線程

若是拋出RuntimeException子類而不是Exception子類,那麼您如何知道應該捕獲的內容?

若是答案是catch Exception那麼您也將以與系統異常相同的方式處理程序員錯誤。 對我來講這彷佛是錯誤的。

若是捕獲Throwable則將以相同的方式處理系統異常和VM錯誤(等等)。 對我來講這彷佛是錯誤的。

若是答案是僅捕獲已知的異常,那麼您如何知道拋出了哪些異常? 當程序員X拋出一個新異常而忘記捕捉它時,會發生什麼? 對我來講這很危險。

我會說顯示堆棧跟蹤的程序是錯誤的。 不喜歡檢查異常的人會不會有這種感受?

所以,若是您不喜歡檢查異常,是否能夠解釋爲何不這樣作並回答未獲得回答的問題?

編輯:我不是在尋找什麼時候使用任何一種模型的建議,我正在尋找的是爲何人們從RuntimeException擴展,由於他們不喜歡從Exception擴展和/或爲何他們捕獲異常而後從新拋出RuntimeException而不是向其方法添加拋出。 我想了解不喜歡檢查異常的動機。


#1樓

嘗試僅解決未解決的問題:

若是拋出RuntimeException子類而不是Exception子類,那麼您如何知道應該捕獲的內容?

該問題包含似是而非的推理恕我直言。 僅僅由於API告訴您它拋出了什麼並不意味着您在全部狀況下都以相同的方式處理它。 換句話說,您須要捕獲的異常取決於使用組件引起異常的上下文。

例如:

若是我正在爲數據庫編寫鏈接測試器,或者要檢查用戶輸入的XPath的有效性的東西,那麼我可能想捕獲並報告該操做引起的全部已檢查和未檢查的異常。

可是,若是我正在編寫處理引擎,則可能會以與NPE相同的方式對待XPathException(已檢查):我會讓它運行到工做線程的頂部,跳過該批處理的其他部分,登陸問題(或將其發送給支持部門進行診斷),並留下反饋讓用戶與支持人員聯繫。


#2樓

咱們已經看到了一些有關C#首席架構師的參考。

這是Java專家關於什麼時候使用檢查的異常的另外一種觀點。 他認可其餘人提到的許多負面因素: 有效例外


#3樓

好的...受檢查的異常不是理想的狀況,但有一些警告,但確實能夠達到目的。 建立API時,某些特定狀況下的失敗是該API的約定。 當在諸如Java之類的高度靜態類型化語言的上下文中,若是一我的不使用檢查的異常,則必須依靠即席文檔和約定來傳達錯誤的可能性。 這樣作會消除編譯器帶來的處理錯誤的全部好處,而您徹底會被程序員的善意所取代。

所以,一個刪除Checked異常,例如在C#中進行的操做,那麼一我的如何以編程和結構方式傳達錯誤的可能性? 如何通知客戶代碼這種錯誤可能發生而且必須加以解決?

在處理受檢查的異常時,我聽到了各類各樣的恐懼,這是能夠確定的,但未經檢查的異常也是如此。 我說等幾年,當API堆疊到很深的層次時,您會乞求某種結構化方法的回報來傳達故障。

以這種狀況爲例,該異常被拋出到API層底部的某個地方,而且因爲沒有人知道甚至可能發生此錯誤而冒泡了,即便這種錯誤類型在調用代碼時很是合理扔掉它(例如FileNotFoundException而不是VogonsTrashingEarthExcept ...在這種狀況下,咱們是否處理它都沒有關係,由於沒有東西能夠處理它了)。

許多人爭辯說,沒法加載文件幾乎老是該過程的末日,它一定會致使可怕而痛苦的死亡。 因此是的..肯定...肯定..您爲某些內容構建了一個API,並在某個時刻加載了文件...做爲該API的用戶,我只能作出響應...「您到底該決定個人時間程序應該崩潰!」 固然能夠,由於能夠選擇在其中吞噬異常而且不留任何痕跡,或者具備比Marianna溝槽更深的堆棧跟蹤的EletroFlabbingChunkFluxManifoldChuggingException,我會絕不猶豫地選擇後者,但這是否意味着這是處理異常的理想方法? 咱們能夠不在中間的地方,在異常遍歷到新的抽象級別時會重鑄幷包裝該異常,以便它實際上意味着什麼嗎?

最後,我看到的大多數論據是「我不想處理異常,許多人不想處理異常。檢查異常迫使我去處理它們,所以我討厭檢查異常」。將其釋放到goto的鴻溝地獄只是愚蠢的,缺少判斷力和遠見。

若是咱們消除了檢查異常,咱們也能夠消除函數的返回類型,而且老是返回「 anytype」變量……那會使生活變得如此簡單,不是嗎?


#4樓

不須要檢查異常的充分證據是:

  1. 許多框架爲Java作一些工做。 像Spring將JDBC異常包裝爲未檢查的異常同樣,將消息拋出到日誌中
  2. Java以後的許多語言,甚至是Java平臺上的頂級語言-它們都不使用它們
  3. 檢查異常,這是有關客戶端如何使用引起異常的代碼的一種預測。 可是編寫此代碼的開發人員永遠不會知道代碼客戶端正在從事的系統和業務。例如,一個Interfcace方法強制拋出已檢查的異常。 系統上有100種實現,其中50種甚至90種實現不會引起此異常,可是若是客戶端用戶引用該接口,則客戶端仍必須捕獲此異常。 那些50或90個實現每每會本身處理這些異常,從而將異常放入日誌中(這對他們來講是好行爲)。 咱們應該怎麼作? 我最好有一些能夠完成全部工做的後臺邏輯-將消息發送到日誌。 並且,若是我做爲代碼的客戶,會以爲我須要處理異常-我會作的。 我可能會忘記它,對-可是,若是我使用TDD,那麼個人全部步驟都已涵蓋,而且我知道我想要什麼。
  4. 當我在Java中使用I / O時的另外一個示例,若是文件不存在,它會強制我檢查全部異常。 我該怎麼辦? 若是不存在,則系統將不會進行下一步。 此方法的客戶端不會從該文件中獲取預期的內容-他能夠處理運行時異常,不然我應該首先檢查Checked Exception,將消息記錄下來,而後從該方法中拋出異常。 否...否-我最好使用RuntimeEception自動執行此操做,它會自動/自動點亮。 手動處理沒有任何意義-我很高興在日誌中看到一條錯誤消息(AOP能夠幫助解決此問題。 若是最終我認爲系統應該向最終用戶顯示彈出消息-我將顯示它,這不是問題。

若是Java在使用I / O之類的核心庫時能爲我提供選擇使用什麼的選項 ,我感到很高興。 Like提供了兩個相同類的副本-一個用RuntimeEception包裝。 而後咱們能夠比較人們會用什麼 。 可是,到目前爲止,許多人最好仍是在Java或其餘語言之上尋求一些框架。 像Scala同樣,JRuby也能夠。 許多人只是認爲SUN是正確的。


#5樓

例外類別

在談論異常時,我老是參考Eric Lippert的Vexing異常博客文章。 他將異常納入如下類別:

  • 致命 -這些異常不是您的錯 :您沒法阻止這種狀況,也沒法明智地處理它們。 例如, OutOfMemoryErrorThreadAbortException
  • 笨拙 -這些異常是您的錯 :您應該阻止它們,它們表示代碼中的錯誤。 例如, ArrayIndexOutOfBoundsExceptionNullPointerException或任何IllegalArgumentException
  • 惱人的 -這些異常不是例外 ,不是您的錯,您沒法阻止它們,但必須處理它們。 它們一般是不幸的設計決定的結果,例如從Integer.parseInt引起NumberFormatException而不是提供Integer.tryParseInt方法,該方法在解析失敗時返回布爾值false。
  • 外在的 -這些異常一般是例外 ,不是您的錯,您不能(合理地)阻止它們,但必須處理它們 。 例如, FileNotFoundException

API用戶:

  • 不得處理致命愚蠢的例外。
  • 應該處理使人煩惱的異常,但它們不該在理想的API中發生。
  • 必須處理外部異常。

檢查異常

API用戶必須處理特定異常的事實是調用方和被調用方之間方法約定的一部分。 合同規定了:被調用者指望的參數的數量和類型,調用者能夠指望的返回值的類型以及調用者但願處理的異常

因爲API中不存在使人煩惱的異常,所以只有這些外部異常必須通過檢查 ,才能成爲方法約定的一部分。 相對較少的異常是外生的 ,所以任何API都應具備相對較少的已檢查異常。

受檢查的異常是必須處理的異常。 處理異常就像吞下它同樣簡單。 那裏! 處理異常。 期。 若是開發人員但願以這種方式處理它,那很好。 可是他不能忽視這個例外,並受到警告。

API問題

可是,任何檢查過煩人致命異常的API(例如JCL)都會給API用戶帶來沒必要要的壓力。 這種異常必須處理,但任何的異常是很常見的,它不該該已經擺在首位的異常,或沒有任何東西能夠在搬運時完成。 致使Java開發人員討厭檢查的異常。

一樣,許多API沒有適當的異常類層次結構,致使全部種類的非外部異常緣由都由單個檢查的異常類(例如IOException )表示。 這也使Java開發人員討厭檢查的異常。

結論

外在異常是那些不是您的錯,沒法避免且應該處理的異常。 它們構成了全部可能拋出的異常的一小部分。 API應該僅具備檢查的外部異常 ,而全部其餘異常均未選中。 這將使API更好,減輕API用戶的負擔,從而減小捕獲全部,吞下或從新拋出未經檢查的異常的需求。

所以,不要討厭Java及其檢查的異常。 取而代之的是,討厭過分使用已檢查異常的API。

相關文章
相關標籤/搜索