異常是軟件系統(tǒng)不可避免的的問題镜粤,軟件系統(tǒng)在運行中難免發(fā)生不可預知的錯誤瞳购,為了避免異常造成軟件自動停止運行造成損失粘优,軟件開發(fā)語言一般提供異常處理機制睹栖。
在Java中定義了兩種程序運行發(fā)生的錯誤卵佛,它們是Error和Exception杨赤,它們都繼承自Throwable類敞斋。從設計上來講Error代表的是不能有程序自己處理的異常,比如內存溢出等疾牲。
Exception代表的是檢查異常植捎,即再編程時必須顯示處理的異常,要么try-catch阳柔,要么拋出方法外焰枢,這是在編譯器檢查的。
區(qū)別于Exception舌剂,它的子類RuntimeException是運行時異常(非檢查)济锄,即不是必需寫代碼處理它,也可以編譯通過霍转。
拋出一個異常;
throw new Throwable("Throwable");
throw new Error("error");
throw new Exception("Exception");
throw new RuntimeException("RuntimeException");
在throw 一個異常之后荐绝,throw 語句后面的代碼不會再運行,立即退出try{}塊或者方法(沒被try包裹時避消,方法不會有返回值低滩,而是把異常沿著函數(shù)棧往上拋出,直到被處理)岩喷。
指定方法拋出異常
public void method() throws Exception {
throw new Exception("exception by method");
}
異常的處理恕沫。可以使用try-catch-finally結構來處理異常均驶,如
try {
HelloWorld helloWorld = new HelloWorld();
helloWorld.method(); //這里會拋出異常
} catch (Throwable t) {
System.out.println(t.getMessage());
}finally {
System.out.println("finally");
}
在上面的代碼中昏兆,try表示監(jiān)控異常代碼枫虏,catch塊是處理異常的代碼妇穴,在發(fā)生異常時才執(zhí)行。finally 不管異常有沒有發(fā)生都會在try和catch之后執(zhí)行隶债。
其中try可以指定多個異常腾它,也可以對不同的異常分別處理
try {
HelloWorld helloWorld = new HelloWorld();
helloWorld.method();
} catch (RuntimeException | Error e) { //處理多種異常
System.out.println(e.getMessage());
}catch (Exception e1){ //單獨處理Exception 的情況
System.out.println(e1.getMessage());
}
finally {
System.out.println("finally");
}
比較值得注意的是當try塊或者catch塊中有return語句的情況下,代碼的執(zhí)行過程死讹,下面以實例說明
public static void main(String[] args) {
System.out.println(testEx());
}
public static String testEx() {
try {
method();
return "try";
} catch (Exception e) {
return "catch";
} finally {
return "finally";
}
}
public static void method() {
throw new RuntimeException("exception by method");
}
輸出結果為
finally
這里要注意的是瞒滴,即使在try塊或者catch塊 有return語句,finally 塊還是會執(zhí)行赞警,這時之前的return結果是被緩存著的凝赛。如果finally 中有return語句低缩,那么直接return finally 中的結果。
自定義異常:
雖然Java提供了足夠多的異常類型,但是自定義異常在業(yè)務當中是非常常見的寇仓。一般的,我們會實現(xiàn)繼承自Exception壳贪,RuntimeException的類型直撤,它們和它們的父類有著一樣的特性祖凫。
異常抑制:
之前提到finally 中的return會替代try catch塊中的return。其實finally 中拋出的異常也會抑制后兩者拋出的異常酬凳,在調用者那里捕獲的是finally 的異常惠况,try catch塊中的異常好像消失了。
public static void main(String[] args) {
try {
testEx();
}catch (Exception e){
e.printStackTrace();
}
}
public static String testEx() {
Exception ex = null;
try {
throw new RuntimeException("ex in try");
} catch (Exception e) {
ex = e;
} finally {
RuntimeException runtimeException = new RuntimeException("ex in finally");
runtimeException.addSuppressed(ex); //添加被抑制的異常
throw runtimeException;
}
}
觀察輸出:
java.lang.RuntimeException: ex in finally
at helloworld.HelloWorld.testEx(HelloWorld.java:27)
at helloworld.HelloWorld.main(HelloWorld.java:14)
Suppressed: java.lang.RuntimeException: ex in try
at helloworld.HelloWorld.testEx(HelloWorld.java:23)
... 1 more
可以發(fā)現(xiàn)宁仔,mian方法捕捉到的異常是finally產生的稠屠,這里我們可以把被抑制的異常手動添加,這樣不會丟失有價值的異常信息翎苫。
Java7新特性 try with resource
當使用需要關閉的一些資源完箩,比如FileStream這些流,往往要在使用完成之后關閉它拉队,一般的實踐是在finally 塊中將它們關閉弊知,但是這樣會導致代碼量相對增多。Java7提供了 try with resource的寫法粱快,Java會自動幫我們關閉這些資源秩彤,即會自動調用對象的close()方法。
一個 try-with-resources 語句可以像普通的 try 語句那樣有 catch 和 finally 塊事哭。在try-with-resources 語句中,任意的 catch 或者 finally 塊都是在聲明的資源被關閉以后才運行漫雷。