上一個文章討論了“編程習慣的問題
”,今天來聊聊關於異常處理的話題。
★空catch語句塊
犯這種錯誤的人比較少,一般發生在剛學會Java或者剛參加工作不久的人身上。
所謂"空catch語句塊"就是在catch語句塊中沒有對異常作任何log處理,導致異常資訊被丟棄掉。一旦程式不能正確運行,由於查不到任何log資訊,只好從頭看代碼,靠肉眼找bug。
★沒有使用finally
很多人在catch語句之後不使用finally語句。由於在try語句中可能會涉及資源的申請和釋放。如果在資源申請之後、資源釋放之前拋出異常,就會發生資源流失(資源流失的嚴重性,上一個文章
已經聊過了)。
★籠統的catch語句塊
有些人為了省事,只在自己模組的最外層程式碼封裝一個try語句塊,然後catch(Exception)。不管捕獲到什麼異常,都作統一log了事。這
種做法比“空catch語句塊”稍好,但由於不能對具體的異常進行具體處理,對一些可恢複的異常(下面會提到),喪失了恢複的機會。而且也可能導致上述提
到的資源流失的問題。
★使用函數傳回值進行錯誤處理
有些人放著Java的異常機制不用,而用函數傳回值來表示成功/失敗(比如返回true表示成功、返回false表示失敗),簡直是“捧著金碗要飯”。個人感覺,從C轉到Java的人比較容易有此毛病。這種做法會導致如下幾個問題:
傳回值一般用整數值或布爾值表示,傳遞的資訊過於簡陋;
一旦調用者忽略了錯誤返回碼,就會導致和“空catch語句塊”類似的問題;
對同一個函數的多處調用,都需要對傳回值進行重複判斷,導致代碼冗餘(代碼冗餘的壞處,上一個文章
也已經聊過了)。
★不清楚Checked Exception和Runtime Exception的區別
這個現象比較普遍,我發現很多2年以上Java工作經驗的人尚未完全搞明白兩者的區別。看來這個問題得詳細說一下。
當初Java的設計者有意區分這兩種異常,是別有深意的。其中“Checked Exception”用於表示可恢複的異常(也就是你必須檢查的異常);而“Runtime Exception”表示不可恢複的異常(也就是運行時異常,主要是程式bug和致命錯誤,你不需要
檢查)。不過這種做法引來了很多爭議(包括很多Java大牛),鑒於本文章主要針對新手,以後再專門來聊這個爭議的話題。
為了便於理解,下面我舉一個例子來說明。假設你要寫一個Download函數,根據傳入的URL(String參數)返回對應網頁的內容文本。這時候有兩種情況你需要處理:
1、如果傳入的URL參數是null,這表明該函數的調用者出bug了,而程式本身的bug是很難在運行時自我恢複的。這時候Download函數必須拋出Runtime Exception。並且Download函數的調用者不應該
嘗試去處理這個異常,必須讓它儘早
暴露出來(比如讓JVM自己終止運行)。
2、如果傳入的URL參數非null,但是它包含的字串不是一個合法的URL格式(可能由於使用者輸入錯誤導致)。這時候Download函數必須拋出
Checked Exception。並且Download函數的調用者必須捕獲該異常並進行相應的處理(比如提示使用者重新輸入URL)。
上面就是幾種常見的Java異常處理的誤用。下一個文章我們來聊一下“對虛擬機器(JVM)瞭解不足
”。
http://program-think.blogspot.com/2009/02/defect-of-java-beginner-4-exception.html