轉載請保留原文鏈接: http://dashidan.com/article/java/basic/16.html
Java異常是Java提供的一種識別及響應錯誤的一致性機制.
① Java異常機制相關關鍵字
Java異常機制相關關鍵字有: try
、catch
、finally
、throw
、throws
.
關鍵字解釋:
- try 用於監聽. 將被監聽的代碼(可能拋出異常的代碼)放在try語句塊之內, 當try語句塊內發生異常時,異常就被拋出.
- catch 用來捕獲try語句塊中發生的異常.
- finally finally語句塊總是會被執行. 主要用於回收在
try
塊裏打開的物理資源(如文件, 網絡連接, 數據庫連接等).
finally語句中return
只有finally塊執行完成之後,纔會執行try或者catch塊中的return或者throw語句. 如果finally中使用了return或者throw等終止方法的語句,則就不會跳回執行,直接停止.
- throw 用於拋出異常.
- throws 用在方法簽名中,用於聲明該方法可能拋出的異常.
② Java異常框架
Java將可拋出(Throwable)的結構分爲三種類型:
- 編譯異常(Checked Exception)
- 運行時異常(RuntimeException)
- 錯誤(Error)
Java異常框架繼承關係如圖:
1.Throwable
Throwable
是Java
語言中所有錯誤或異常的超類, 包含兩個子類:Error
和Exception
.它們通常用於指示發生了異常情況.Throwable
包含了其線程創建時線程執行堆棧的快照,提供了printStackTrace()
等接口用於獲取堆棧跟蹤數據等信息.
2.運行時異常RuntimeException
RuntimeException
是那些可能在Java
虛擬機正常運行期間拋出的異常的超類, 簡稱運行時異常
. RuntimeException及其子類都被稱爲運行時異常.
Java編譯器不會檢查運行時異常.當程序中可能出現這類異常時,倘若既”沒有通過throws聲明拋出它”,也”沒有用try-catch語句捕獲它”,還是會編譯通過.
雖然Java編譯器不會檢查運行時異常, 但是我們也可以通過throws進行聲明拋出, 也可以通過try-catch對它進行捕獲處理. 如果產生運行時異常,則需要通過修改代碼來進行避免.
例如:
* 除數爲零時產生的ArithmeticException異常
* 數組越界時產生的IndexOutOfBoundsException異常
* fail-fail機制產生的ConcurrentModificationException異常等,都屬於運行時異常.
異常 | 描述 |
ArithmeticException | 除數爲零異常 |
ArrayIndexOutOfBoundsException | 數組越界 |
ClassCastException | 對象轉型錯誤 |
IllegalArgumentException | 參數不合法 |
IndexOutOfBoundsException | 指示某排序索引(例如對數組、字符串或向量的排序)超出範圍 |
NegativeArraySizeException | 數組長度爲負值 |
NullPointerException | 空指針異常 |
NumberFormatException | 當應用程序試圖將字符串轉換成一種數值類型,但該字符串不能轉換爲適當格式時,拋出該異常. |
3.編譯異常Exception
Exception
類以及Exception
的子類中除了”運行時異常”之外的其它子類都屬於被檢查異常. 此類異常,要麼通過throws進行聲明拋出,要麼通過try-catch進行捕獲處理,否則不能通過編譯.
異常 | 描述 |
ClassNotFoundException | 應用程序試圖加載類時,找不到相應的類,拋出該異常. |
FileNotFoundException | 文件不存在異常 |
ClassCastException | 對象轉型錯誤 |
InterruptedException | 一個線程被另一個線程中斷,拋出該異常. |
NoSuchFieldException | 請求的變量不存在 |
NoSuchMethodException | 請求的方法不存在 |
4.Error
Error
類及其子類統稱錯誤
. 用於指示試圖捕獲的嚴重問題, 大多數這樣的錯誤都是異常條件. 和運行時異常
一樣, 編譯器也不會檢查Error
. 當資源不足、約束失敗、或是其它導致程序無法繼續運行的條件發生時, 就產生錯誤. 程序本身無法修復這些錯誤.
例:
- VirtualMachineError就屬於錯誤.
-
按照Java慣例, 不應該實現任何新的Error子類, 需要自定義異常可以採用Exception類.
到底該哪一種異常?
對於可以恢復的條件使用被檢查異常,對於程序錯誤使用運行時異常.虛擬機及系統錯誤採用Error.
③ 捕獲異常
使用try
和catch
關鍵字可以捕獲異常.try/catch
代碼塊放在異常可能發生的地方.
語法如下:
try {
/** 程序代碼*/
} catch (Exception e) {
/** 異常處理*/
}
一個`try`代碼塊後面跟隨多個`catch`代碼塊的情況就叫多重捕獲. 可以在 try 語句後面添加任意數量的 catch 塊.
如果保護代碼中發生異常,異常被拋給第一個 catch 塊. 如果拋出異常的數據類型與捕獲異常類型匹配, 就會被捕獲.
如果不匹配,它會被傳遞給下一個`catch`塊.直到異常被捕獲或者通過所有的`catch`塊.
語法如下:
try {
/** 程序代碼*/
} catch (Exception1 e) {
/** 異常處理*/
} catch (Exception1 e) {
/** 異常處理*/
}
④ 拋出異常
可以使用throw
關鍵字拋出一個異常.
public static void testThrow() {
/** 方法體*/
throw new NullPointerException();
}
如果一個方法沒有捕獲一個`編譯異常`, 那麼該方法必須使用`throws`關鍵字來聲明. `throws`關鍵字放在方法簽名的尾部.
示例代碼:
public static void testThrows() throws NullPointerException {
/** 方法體*/
}
一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開.
例如,下面的方法聲明拋出`NullPointerException`和`ArithmeticException`
示例代碼:
public static void testThrows() throws NullPointerException, ArithmeticException {
/** 方法體*/
}
⑤ finally關鍵字
finally
關鍵字用來創建在try
代碼塊後面執行的代碼塊. 無論是否發生異常,finally
代碼塊中的代碼總會被執行. 在finally
代碼塊中,可以運關閉鏈接, 釋放系統資源等必須要執行的語句.
finally
代碼塊出現在catch
代碼塊最後.
語法如下:
try {
/** 方法體*/
} catch (Exception e) {
/** 異常處理*/
} finally {
/** finally語句*/
}
finally 塊並非強制添加.
try 代碼後不能既沒 catch 塊也沒 finally 塊.
示例代碼:
package com.dashidan.lesson15;
/**
* 大屎蛋教程網-dashidan.com
* <p>
* Java教程基礎篇: 15.Java異常
* 測試finally return
*/
public class Demo2 {
public static void main(String[] args) {
int result = testFinallyReturn();
System.out.println("result: " + result);
}
public static int testFinallyReturn() {
int a;
try {
a = 1;
/** 拋出異常*/
System.out.println("拋出異常");
throw new NullPointerException();
} catch (NullPointerException e) {
a = 2;
/** 捕獲異常*/
System.out.println("捕獲異常");
e.printStackTrace();
/** 注意這裏沒有返回*/
System.out.println("注意這裏沒有返回");
return a;
} finally {
a = 3;
System.out.println("finally執行返回");
/** 拋出異常後, 執行finally的語句, 如果這裏返回,不再執行catch中語句*/
return a;
}
}
}
輸出:
拋出異常
捕獲異常
注意這裏沒有返回
finally執行返回
result: 3
java.lang.NullPointerException
at com.dashidan.lesson15.Demo2.testFinallyReturn(Demo2.java:21)
at com.dashidan.lesson15.Demo2.main(Demo2.java:11)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
⑥ 自定義異常
在Java
中自定義異常需要注意:
- 所有異常都必須是 Throwable 的子類.
- 如果想寫一個檢查性異常類,則需要繼承 Exception 類.
- 如果想寫一個運行時異常類,那麼需要繼承 RuntimeException 類.
package com.dashidan.lesson15;
/**
* 大屎蛋教程網-dashidan.com
* <p>
* Java教程基礎篇: 15.Java異常
* 自定義異常
*/
public class SelfException extends Exception {
}
示例代碼:
package com.dashidan.lesson15;
/**
* 大屎蛋教程網-dashidan.com
* <p>
* Java教程基礎篇: 15.Java異常
*/
public class Demo1 {
public static void main(String[] args) {
try {
/** 方法體*/
testThrow();
testThrows();
} catch (NullPointerException e) {
/** 異常處理*/
System.out.println("run catch NullPointerException.");
e.printStackTrace();
} catch (Exception e) {
/** 異常處理*/
System.out.println("run catch Exception.");
e.printStackTrace();
} finally {
/** finally語句*/
System.out.println("run finally.");
}
}
public static void testThrow() {
/** 方法體*/
throw new NullPointerException();
}
public static void testThrows() throws NullPointerException, ArithmeticException {
/** 方法體*/
}
}
輸出:
java.lang.NullPointerException
at com.dashidan.lesson15.Demo1.testThrow(Demo1.java:30)
at com.dashidan.lesson15.Demo1.main(Demo1.java:12)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
run catch NullPointerException.
run finally.