今年有個目標之一就是提升團隊程式碼的質量,所以時常會思索如何把這件事做到更好,不想教條主義,也不想搞出一個程式碼規範,強制團隊照著做,落地的效果不好,反而把大家的積極性給弄沒了。所以我的原則是,我們一起看看什麼事是我們不能做的,排除掉,剩下的就是我們可以做的,同時真正搞清楚問題在哪裡,而不是簡單的模仿。從我個人的經驗看,程式碼優化中最重要的一點就是對異常情況的處理。今天,我就借這個話題,談談如何來優化我們的程式碼。
坑1:捕捉異常不做處理
如下段程式碼所示,不知道各位在自家的程式碼中見過多少,我是期望大家不要遇見。且不說printStackTrace()這樣的程式碼就不應該出線在正式的上線程式碼中,不做處理本身這會導致業務的潛在問題被隱藏了,所以這個坑是我認為異常處理中最糟糕的一點。
try
{
....
}
catch(Exception ex)
{ex.printStackTrace();
System.out.println(XXX);
}
對於異常的捕捉處理,遵循以下的流程:
處理該異常,執行具體的邏輯處理,加上必要的系統日誌記錄 (log4j,logcat ...)。
涉及其他系統或者上一級系統,需要轉換成對應的訊息通知相關係統。上一級是前端,需要轉換成前端可以“讀懂”的錯誤提示。
無法處理該異常或者該異常需要上一級統一處理,Throw out該異常。
坑2:不處理資源釋放
還是見程式碼說話,如果append出錯,那麼IO流就不會被關掉,那麼最終就會導致整個程式因為溢位崩掉。
FileWriter fileWriter = null;
try
{
fileWriter = new FileWriter("");
fileWriter.append(item.toString());
fileWriter.close();
}
catch (IOException e)
{
...
}
在使用檔案、IO流、資料庫連線等不會自動釋放的資源時,應該在使用完畢後馬上將其關閉。關閉資源的程式碼try...catch...finally的finally內執行,否則就可能因為Exception的原因造成資源無法釋放。
坑3:對異常不進行分類處理
程式碼中,最容易看到的一種情況就是設定catch的異常型別是Exception, 並且只有一套處理邏輯, 如下:
try{
...
}
catch (Exception e){
...
}
這裡的問題主要有以下兩點:
1. catch的不同Exception,可能需要執行不同的處理邏輯,一個catch要同時處理所有邏輯就很難實現。
2. 由於是捕捉的基類Exception, 那麼RuntimeException也會被捕捉到,如果稍微不注意的話,RuntimeException最終沒有任何實際處理,程式碼中的真正錯誤被掩蓋掉了。
所以,正確的做法應該是按照具體的異常進行分類處理, 例如:
try{
...
}
catch (FileNotFoundException e){
// alert that the specified file
// does not exist
}
catch (EOFException e){
// alert that the end of the file
// was reached
}
catch (ObjectStreamException e){
// alert that the file is corrupted
}
catch (IOException e){
// alert that some other I/O
// error occurred
}
坑4:將大段程式碼放進一個Try-Catch中
有時可以看到,一些程式碼的作者恨不得把整個函式裡的實現程式碼都放入單個try中,原因就在於為了圖省事,不願花時間分析一大塊程式碼中哪幾行程式碼會丟擲什麼異常、異常的具體型別是什麼,應該如何處理。這樣的做法導致異常發生後,後續除錯找問題更麻煩,一大段程式碼中有太多的地方可能丟擲Exception。這樣的做法導致,很難去統計和判斷要catch哪一些型別的Exception, 只能寫一個粗糙的Exception, 又掉進我們說的第3個坑裡。
一點總結
在和大家一起分析了上面的異常坑後,如果未來我們想避免踩進一個異常坑,編寫異常程式碼可以遵循以下三個點:
1. 出了什麼錯?
2. 在哪出的錯?
3. 為什麼出錯?
掃描二維碼或手動搜尋微信公眾號【架構棧】: ForestNotes
歡迎轉載,帶上以下二維碼即可