在編寫代碼的過程當中,常常會遇到這樣的選擇,檢查到一個不正常的狀況,或者某個操做失敗,或者檢測到
某個異常,此後該怎麼辦?是拋出一個異常?仍是放回一個表示操做失敗的返回值?
前一段在北京和小湯他們談起這個問題的時候,有了一些粗略的想法。這段時間在 Leo4Net 的開發中,一些
想法逐步清晰起來。
=== abc ===
=== 兩種方式的不一樣 ===
× 返回值很容易被檢測,而捕獲異常的代碼則相對比較長
× 拋出以及捕獲異常須要更多的系統開銷
× 若是忽略返回值,調用者能夠繼續,但沒有捕獲的異常則將終止調用者的執行
=== 應該拋出異常的幾種狀況 ===
在這些狀況下,應該是要拋出異常的:
=== 沒法經過參數檢查 ===
例如空值、參數取值範圍等,由於參數的規則說明是做爲方法簽名的一部分發布的,調用者應該很清楚
調用這個方法所須要的參數的規格,可是調用者如今傳入的錯誤的參數,說明調用者自己這時候極可能
就已經出現問題了。
對參數進行檢查自己也是一個編寫一個方法的良好習慣,這能夠保證方法自己在一個相對比較穩定可知
道狀態下工做,所以方法自己將更簡單也更穩定。
總之,拒絕非法的參數,並拋出異常。
=== 將可能致使之後的相關功能出錯 ===
若是一個異常或者錯誤的參數將致使之後更多的異常或者之後的某個功能異常,那麼不要延遲,當即拋
出異常。
例若有一個屬性 Filename 用來保存將被保存的文件的名稱,一個的方法 Save 將保存到 Filename 所
指定的文件名中去,顯然在給 Filename 屬性賦值時,若是給出一個包含非法文件名字符的字符串,那
麼將致使 Save 方法中會有異常發生,不論 Save 方法是否對 Filename 再進行檢查,這時候距離設定
Filename 的代碼可能已經至關遠了,所以在設定 Filename 的時候,就應該要進行這種有關的檢查,
若是文件名不合法,當即拋出異常,而不要等到之後再來發現這個問題。
上述對參數進行檢查其實不少也是這種狀況,特別一些空值參數,將可能致使之後使用該參數的時候發
生空值異常。
=== 不該該拋出異常的幾種狀況 ===
=== 不影響程序繼續運行 ===
若是一個錯誤並不影響程序邏輯的正確性,或者不影響此後代碼的繼續運行,那麼能夠沒必要拋出異常。
一個典型的例子例如,從集合中刪除指定鍵值對應的元素,但指定的鍵值其實並不在集合中,這顯然是
一個意外狀況,可是,就此繼續下去,之後的程序應該還能夠繼續有效的運行,由於即便在正常狀況下
也不過是這個元素再也不存在於集合中而已。返回一個整數值表示刪除掉的元素的個數,若是沒有找到給
定的元素,則返回0表示沒有元素被刪除。這個例子的另外一種情形是,當前集合元素由於某種緣由被鎖住
不能刪除元素,那麼應該拋出一個異常表示刪除失敗,而不是返回0表示沒有刪除元素。
別人評論:程序員
很是贊同。
對於這種難以明確界定的問題,一方面有大原則,但有時候還須要視實際狀況酌情處理。「將可能致使之後的相關功能出錯」,個人理解是這樣的:對於必定致使之後出錯的狀況,決定拋出異常——由於一個出錯的軟件接下來只能產生負面功效;對於可能出錯也可能不錯的狀況,能夠延遲拋出異常,在真正碰到錯誤時應該有更高層的異常捕捉,甚至平臺——由於拋出異常是有代價的,若是在有但願的時候立刻帶來損失,相信有時候不可取,而若是不拋出異常會帶來更大損失,也許就當即拋出了。總之,我以爲軟件的穩定性要求不一樣,選擇是有區別的。這也許是程序員的抉擇——但最終是需求的抉擇。
方法始終對參數有效性進行檢測——真的很重要。
不少時候,你們想到了異常,在怎樣拋出異常的話題下面,怎麼詳細地定義可預見的異常、儘可能避免異常產生的損失、儘可能修復和彌補,是一個穩定健壯軟件必須作好的事情。開發