出自《深夜裡的程式猿》
前言不管在我們的工作還是生活中,總會出現各種「錯誤」,各種突發的「異常」。無論我們做了多少準備,多少測試,這些異常總會在某個時間點出現,如果處理不當或是不及時,往往還會導致其他新的問題出現。所以我們要時刻注意這些陷阱以及需要一套「最佳實踐」來建立起乙個完善的異常處理機制。
正文異常分類
首先,這裡我畫了乙個異常分類的結構圖。
在jdk中,throwable是所有異常的父類,其下分為」error「和」exception「。error意味著出現了不可控的嚴重錯誤,例如outofmemoryerror。exception則細分為兩類,受檢異常(check)需要我們手動try/catch或者在方法定義中throws,編譯器在編譯的時候會檢查其合法性。非受檢異常(uncheck)則不需要我們提前處理。這些簡單的概念對於開發人員來說都是必須掌握的,這裡就展示個圖例,不做詳細的描述了,我們的」正餐「還在後面。
重新認識try/catch/finally
說到異常處理,這裡就不得不提try/catch/finally。try不可以單獨存在,要麼搭配catch,要麼搭配finally,或者三者並存。
1、try**塊:監視**塊的執行,發現對應的的異常則跳轉至catch,若無catch則直接到finally塊。
2、catch**塊:發生對應的異常會執行裡面的**,要麼處理,要麼向上丟擲。
3、finally**塊:不管是否有異常,都必執行,一般用來清理資源,釋放連線等。然而有以下幾種情況不會執行到這裡的**。
**執行流程未進入try**塊。
**在try**塊中發生死迴圈、死鎖等狀態。
在try**塊中執行了system.exit()操作。
try/catch/finally陷阱
下面介紹兩個我們在使用tcf的時候可能會遇到的陷阱。
**1public class tcfdemo finally finally {
lock.unlock();
陷阱2:由於lock方法在加鎖的時候有可能會丟擲uncheck異常,如果在try**塊中,必然會執行unlock方法,此時由於並沒有加鎖成功,所以會丟擲illegalmonitorstateexception,這樣一來後者的異常就覆蓋掉了前者加鎖失敗的異常資訊,所以我們應該把加鎖的方法挪至try**塊外面。
最佳實踐
好了,前面簡單介紹了異常的分類以及try/catch/finally的注意事項,現在可以總結一下我們在異常處理的時候有哪些」最佳實踐「了。
當需要向上丟擲異常的時候,需根據當前業務場景定義具有業務含義的異常,優先使用行業內定義的異常或者團隊內部定義好的。例如在使用dubbo進行遠端服務呼叫超時的時候會丟擲dubbotimeoutexception,而不是直接把runtimeexception丟擲。
請勿在finally**塊中使用return語句,避免返回值的判斷變得複雜。
捕獲異常具體的子類,而不是exception,更不是throwable。這樣會捕獲所有的錯誤,包括jvm丟擲的無法處理的嚴重錯誤。
切記更別忽視任何乙個異常(catch住了不做任何處理),即使現在能確保不影響邏輯的正常執行,但是對於將來誰都無法保證**會如何改動,別給自己挖坑。
不要使用異常當作控制流程來使用,這是乙個很奇葩也很影響效能的做法。
清理資源,釋放連線等操作一定要放在finally**塊中,防止記憶體洩漏,如果finally塊處理的邏輯比較多且模組化,我們可以封裝成工具方法呼叫,**會比較簡潔。
結尾小小的異常,有大大的學問,你覺得呢?
Java異常處理最佳實踐及陷阱防範
前言不管在我們的工作還是生活中,總會出現各種 錯誤 各種突發的 異常 無論我們做了多少準備,多少測試,這些異常總會在某個時間點出現,如果處理不當或是不及時,往往還會導致其他新的問題出現。所以我們要時刻注意這些陷阱以及需要一套 最佳實踐 來建立起乙個完善的異常處理機制。正文異常分類 首先,這裡我畫了乙...
Java最佳實踐
宗旨 清晰,簡單 可重用模組不能太大不能太小 模組間依賴盡可能小 1,初始化和銷毀物件 使用static factory methods代替構造方法 valueof 為型別轉換方法 getinstance 為返回乙個物件 單例 public class foo public static foo g...
java程式設計最佳實踐
不應該像下面這樣 string ordername urlencoder.encode 這裡是中文 constant.charset utf finally語句只能做如下事件 1 關閉io資源,比如關閉inputstream或socket 2 只做列印錯誤資訊,捕獲異常,不要丟擲異常 儲存在資料庫中...