1JAVA異常
異常指不期而至的各種狀況,如:文件找不到、網絡連接失敗、內存越界等。異常是一個事件,它發生在程序運行期間,干擾了正常的指令流程。Java通過API中Throwable類的衆多子類描述各種不同的異常。因而,Java異常都是對象,是Throwable子類的實例,描述了出現在一段編碼中的錯誤條件。當條件生成時,錯誤將引發異常。
Java異常類層次結構圖:
這裏需要針對兩個重要的子類說明,Exception(異常)和 Error(錯誤)。
Error(錯誤):是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。
大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,OutOfMemoryError、NoClassDefFoundError、StackOverFlowError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。
Exception(異常):是程序本身可以處理的異常。
如上圖,它又分爲IO異常和運行時異常。我們平時最常見的就是運行時異常。比如NullPointerException、ArrayIndexOutOfBoundException等。
同時Java的異常(包括Exception和Error)又分爲可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。
可查異常:簡單理解爲,Java編譯器或者IDE會檢查它,會有提示錯誤信息。除 了RuntimeException及其子類以外,其他的Exception類及其子類都屬於可查異常,如IOException,SQLException。當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,否則編譯不會通過。
不可查異常:反之,編譯器不要求強制處置的異常就是不可查異常。包括RuntimeException與其子類和錯誤(Error),如NullPointerException等常見異常。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度儘可能避免這類異常的發生。我們現在接觸最多的也是現在要講的就是這類異常處理。
2、異常處理機制
在 Java 應用程序中,異常處理機制爲:拋出異常,捕捉異常。
拋出異常使用throws子句或者throw new Exception()。
捕捉異常通過try-catch語句或者try-catch-finally語句實現。
總體來說,Java規定:對於可查異常必須捕捉、或者聲明拋出。允許忽略不可查的RuntimeException和Error。但是,我們提倡所有的運行時異常都要進行捕捉處理,或者拋給方法的調用者。否則出現問題,只會給用戶展現一些不友好的錯誤代碼。或者不拋出也不捕捉處理,導致方法的調用者沒有任何消息,一頭霧水。
下面我們以實際開發來說明兩種處理機制的配合使用,達到系統的友好性和穩定性。
3.1 異常捕捉
Java中用try-catch塊來捕捉可能發生的異常。以代碼來說明:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public void core() throws Exception { try { String a = "" ; Integer.valueOf(a); //製造一個java.lang.NumberFormatException異常 System.out.println( "1、***" ); } catch (Exception ex) { System.out.println( "2、***" ); ex.printStackTrace(); throw ex; //第二種情況 } finally { System.out.println( "3、***" ); } System.out.println( "4、***" ); } |
這裏分兩種情況,一種是在catch子句中捕捉處理異常,但不向上throw異常;一種就是捕捉處理並且向上拋出異常。
1
2
3
4
|
//第一種輸出結果: 2 、*** 3 、*** 4 、*** |
1
2
3
|
//第二種輸出結果: 2 、*** 3 、*** |
解說:第二種情況向上拋出異常後,當前線程就會中斷,try-catch塊後面的代碼就不會執行,這裏平時可能需要注意。當選擇向上拋出異常的時候,調用者要麼用try-catch捕捉處理,要麼繼續向上拋出。
建議:方法是向上拋出異常還是捕捉異常進行處理,這需要根據當前方法所處的代碼層級。以Java開發中典型的三層架構來講。第一層爲API層或者叫接口層,供外部調用,第二層爲server層或者叫業務層,這裏仍不是真正的代碼處理,也只是做一些參數的封裝之類的;第三層就是core層,核心層,這層主要是寫代碼來實現功能,比如查詢數據庫,調用第三方接口等。
經驗:從系統架構的鬆耦合和實現上來講,API層和Server層不做異常的處理工作,全部的異常處理交給core層來處理之後,返回定義好的錯誤代碼和錯誤信息給上層,最後由API層將錯誤信息返回到顯示層展示。同時在core層代碼中的catch子句中打印輸出的堆棧錯誤信息,供開發者分析錯誤原因。
那麼什麼時候需要方法拋出異常呢?
比如在core層中,有一個業務方法比較複雜,那麼就需要將代碼重構,抽出多個子方法來單獨處理,只在主方法中一次調用抽出的子方法。那麼此時,子方法中就需要進行異常拋出了,否則主方法在執行到其中的一個方法時,調用子方法遇到異常時就不知道發生什麼了,線程仍然會繼續調用接下來的方法,那此時系統就比較脆弱了,而且會出現各種問題。