一 處理原則
Java異常代碼中我們使用異常的目的是讓異常的異常類型來提示“什么”被拋出了--- 即出了什么問題;用異常的棧打印信息來跟蹤異常在“哪里”拋出 --- 即哪里出了問題;
異常提示信息來提示“為什么”會拋出 --- 即出問題的原因。在對異常進行處理時,遵循以下原則可以有助於在調試過程中最大限度的使用好異常。
- 具體明確
- 提早拋出
- 延遲捕獲
1.具體明確
具體明確指的是在拋出異常時需要針對具體問題來拋出異常,拋出的異常要足夠具體詳細;在捕獲異常時需要對捕獲的異常進行細分,這時會有多個catch語句塊,這幾個catch塊中間泛化程度越低的異常需要越放在
前面捕獲,泛化程度高的異常捕獲放在后面,這樣的好處是如果出現異常可以近可能得明確異常的具體類型是什么。
例如 FileInputStream 的一個構造方法如下, 對file對象做檢查后判斷file是否有效,如果無效直接拋出FileNotFoundException,而不是IOException或者其他更寬泛的Exception
public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); } if (name == null) { throw new NullPointerException(); } if (file.isInvalid()) { throw new FileNotFoundException("Invalid file path"); } fd = new FileDescriptor(); fd.attach(this); path = name; open(name); }
同樣的,在對異常做捕獲處理時,也需要做到具體明確,以下try語句塊中read()和close方法均會拋出IOException而FileInputStream()拋出的是FileNotFoundException
事實上FileNotFoundException繼承自IOException,用一個IOException 就可以囊括所有的異常,這里仍然使用了兩個catch塊來分別捕獲,為的就是方便定位異常問題。
public void foo1(String fileName){ File file = new File(fileName); InputStream in = null; try { in = new FileInputStream(file); Integer num = in.read(); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); } }
2.提早拋出
提早拋出的基本目的還是為了防止問題擴散,這樣出現異常的話排查起來會比較耗時,比較典型的一種情況是 NPE(NullPointerException),當某個參數對象為null時,如果不提早判斷並拋出異常的話,這個null可能
會藏的比較深,等到出現NPE時就需要往回追溯代碼了。這樣就給排查問題增加了難度。所以我們的處理原則是出現問題就及早拋出異常。
例如 上面FileInputStream 的構造方法,在使用前就對File 的path做了判斷,如果為null 就及早的拋出NullPointerException,防止在后面open方法中傳入一個null,從而簡化了出現異常的情況,方便定位問題。
3.延遲捕獲
延遲捕獲說的是對異常的捕獲和處理需要根據當前代碼的能力來做,如果當前方法內無法對異常做處理,即使出現了檢查異常也應該考慮將異常拋出給調用者做處理,如果調用者也無法處理理論上他也應該繼續上拋,
這樣異常最終會在一個適當的位置被catch下來,而比起異常出現的位置,異常的捕獲和處理是延遲了很多。但是也避免了不恰當的處理。
二 處理技巧
對於異常的處理,能避免的異常,盡量在事先做判斷來避免異常的發生,當判斷時發現邏輯上已經不能往下走了,需要停止流程,這時候將異常拋出並准確的提示使用者問題所在。
對於事先無法預判的異常需要對其進行處理。
異常分運行時異常 RuntimeException 和 檢查異常Checked Exception,運行時異常一般用在由於接口方法使用不當的時候
如: 使用了null獲取屬性方法, 數組下標越界,除法運算除以0等
- 如果你調用服務方法的方式不正確,你應該馬上修改代碼,避免發生RuntimeException
- 如果是用戶方法調用你的方法的方式不正確,你應該立刻拋出RuntimeException,強制讓使用者修正代碼或改變使用方式,防止問題蔓延
- 一般情況下,不要捕獲或聲明RuntimeException,需要做的是完善程序代碼。因為問題在於你的程序本身有問題,如果你用異常流程處理了,反而讓正常流程問題一直存在
對於檢查異常,一般先看能不能處理,能處理的異常使用try-catch 語句塊捕獲處理,不能處理使用throws 分類型拋出給上一級處理
使用try-catch語句塊處理時一般需要注意以下幾方面
- try語句塊內要分清穩定代碼和非穩定代碼,對於穩定的不會出現異常的代碼不要放到try語句塊中
- catch捕獲的異常一定要處理
- 若使用了finally 語句塊,在語句塊內一定要對資源對象,流對象進行關閉(jdk1.7之后 可以使用try-with-resources替代)
- finally中不要使用return語句,因為finally語句塊最后一定會執行,這里的return語句會覆蓋之前的return語句
參考:
[1] 有效處理javay異常的三個原則
[2] 阿里巴巴Java開發手冊
