Java 異常處理基本規則,Java異常處理的基本規範
看了團隊中原來程式碼中的異常處理,心碎了一地,稍微對照阿里巴巴的異常處理規範整理了一遍,準備分享一下,Java的異常處理規範&約束。
一、執行異常的撲捉
不要捕獲 Java 類庫中定義的繼承自 RuntimeException
的執行時異常類,如:IndexOutOfBoundsException
/ NullPointerException
,這類異常由程式設計師預檢查來規避,保證程式健壯性。
正例:
-
if(null != obj) {
-
//TODO
-
}
反例:
-
try {
-
obj.method()
-
} catch(NullPointerException e){
-
//TODO
-
}
二、 try-catch 作用域(現有程式碼出現率較高)
對大段程式碼進行try-catch
,這是不負責任的表現。catch
時請分清穩定程式碼和非穩定程式碼,穩定程式碼指的是無論如何不會出錯的程式碼。對於非穩定程式碼的 catch
儘可能進行區分異常型別,再做對應的異常處理。
正例:
分塊
catch
,或者直接丟擲相對應的異常,然後由下層細化處理。
-
map.put("status", 500);
-
try{
-
//程式碼省略
-
map.put("message", "success!");
-
map.put("status", 200);
-
} catch (UnknownHostException e) {
-
//域名錯誤
-
map.put("message", "請輸入正確的網址");
-
LoggerUtils.fmtError(e, "網址異常[%s]", url);
-
} catch (SocketTimeoutException e) {
-
//超時
-
map.put("message", "請求地址超時");
-
LoggerUtils.fmtError(e, "請求地址超時[%s]", url);
-
-
} catch (Exception e) {
-
//其他異常
-
map.put("message", "請求出現未知異常,請重試!\r\n" + e.getMessage());
-
LoggerUtils.fmtError(e, "請求出現未知異常,請重試![%s]", url);
-
}
-
return map;
反例:
-
try {
-
//此處省略1024行程式碼
-
} catch(Exception e){
-
//TODO
-
}
三、異常的捕捉 & 異常的處理(現有程式碼出現率較高)
捕獲異常是為了處理它,不要捕獲了卻什麼都不處理而拋棄之,如果不想處理它,請將該異常拋給它的呼叫者。最外層的業務使用者,必須處理異常,將其轉化為使用者可以理解的內容。
正例:
-
try{
-
//程式碼省略
-
} catch (UnknownHostException e) {
-
//域名錯誤
-
map.put("message", "請輸入正確的網址");
-
LoggerUtils.fmtError(XXXXManager.class, e, "網址異常[%s]", url);
-
} catch (SocketTimeoutException e) {
-
//超時
-
map.put("message", "請求地址超時");
-
LoggerUtils.fmtError(XXXXManager.class, e, "請求地址超時[%s]", url);
-
-
} catch (Exception e) {
-
//其他異常
-
map.put("message", "請求出現未知異常,請重試!\r\n" + e.getMessage());
-
LoggerUtils.fmtError(XXXXManager.class, e, "請求出現未知異常,請重試![%s]", url);
-
}
只為描述一下異常,繼續丟擲。
-
try{
-
//程式碼省略
-
} catch (UnknownHostException e) {
-
throw new HNException("xxx處理失敗。",e);
-
}
反例:
1.如下,呼叫者對異常沒有任何感知。
-
try{
-
//程式碼省略
-
} catch (Exception e) {
-
System.out.println("插入異常");
-
}
2.如下,呼叫者對異常無法定位和判斷
-
try{
-
//程式碼省略
-
} catch (UnknownHostException e) {
-
throw new RuntimeException("500");
-
}
四、異常 & 事務
-
有
try
塊放到了事務程式碼中,catch
異常後,如果需要回滾事務,一定要注意手動回滾事務。 -
在有事務的程式碼中,
catch
異常後,做描述異常等處理後,如果需要事務生效,請把異常繼續丟擲。
五、異常 & finally
1.如果有對IO
流和資源做操作,必須逐一關閉IO
流和資源物件(從裡層到外層),有異常也要做處理。
try{
-
//程式碼省略
-
} catch (Exception e) {
-
throw new HNException("xxx處理失敗。",e);
-
-
}finally{
-
-
try {
-
if(null != conn){
-
conn.disconnect();
-
}
-
} catch (Exception e1) {
-
LoggerUtils.fmtInfo("請求完畢關閉流出現異常![%s]", url);
-
}
-
try {
-
if(null != outStream){
-
outStream.close();
-
}
-
} catch (Exception e2) {
-
LoggerUtils.fmtInfo("請求完畢關閉流出現異常![%s]", url);
-
}
-
try {
-
if(null != out){
-
out.close();
-
}
-
} catch (Exception e3) {
-
LoggerUtils.fmtInfo("請求完畢關閉流出現異常![%s]", url);
-
}
-
-
}
JDK 7 以上可以使用try-with-resources
方式。
六、finally & return
不能在 finally
塊中使用 return
,finally
塊中的 return
返回後方法結束執行,不會再執行 try
塊中的 return
語句。
七、異常需要精確
捕獲異常與拋異常,必須是完全匹配,或者捕獲異常是拋異常的父類。如果預期對方拋的是繡球,實際接到的是鉛球,就會產生意外情況。
八、程式設計師的基本修養 & NPE(現有程式碼中出現率較高)
1.方法(介面)的返回值可以為 null
,但不推薦返回空集合,或者空物件等,必須添加註釋充分說明什麼情況下會返回 null
值。呼叫方需要進行 null
判斷防止 NPE
問題。
2. 防止 NPE
,是程式設計師的基本修養,注意 NPE
產生的場景。
a.查詢資料庫返回null
,包括null
物件和null
集合。
b.集合內元素有null
物件。