Java 異常從精通到陌生
一.什麼的異常?
異常(不同于尋常的)指的是在程式運作過程中發生的異常事件,通常是由外部問題(如硬體錯誤、輸入錯誤)所導緻的。在Java等面向對象的程式設計語言中異常屬于對象。
在Java中通過Throwable類的各種子類來描述不同的異常。
二.為什麼使用異常機制
- 可讀性
- 可靠性
- 可維護性
三.Java異常層次結構
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLiAzNfRHLGZkRGZkRfJ3bs92YsYTMfVmepNHL3lFRPFzaE50dRpHW4Z0MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3AjMxIzN0EjMwITMwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
Throwable
Throwable 是 Java 語言中所有錯誤與異常的超類。表示任何可以作為異常被抛出的類。
Error
編譯時和系統錯誤,程式中無法處理。
Exception
程式本身可以捕獲并且可以處理的異常。
- RuntimeException
四.使用
聲明 throws
用于聲明改方法可能抛出異常
public void throwsException() throws IOException{
}
抛出 throw
public void throwsException() throws IOException {
throw new IOException();
}
捕獲 catch
catch 語句塊中可以捕獲多個異常類型,并對不同類型的異常做出不同的處理
public void catchException(){
try {
throwsException();
} catch (IOException e) {
//如果不處理可以聲明異常繼續抛出
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
}
同一個 catch 也可以捕獲多種類型異常,用 | 隔開
public void catchException(){
try {
throwsException();
} catch (IOException | Exception e) {
//如果不處理可以聲明異常繼續抛出
e.printStackTrace();
}
}
最後 finally
finally用于将資源恢複到它們的初始狀态。如:以打開的檔案或者網絡連結
public void BufferedWriter() {
final File file = new File("C:/Users/TheBlindM/Desktop/gbk.txt");
FileWriter fileWriter =null;
PrintWriter printWriter = null;
try {
fileWriter = new FileWriter(file);
printWriter = new PrintWriter(fileWriter);
while (true) {
printWriter.println("hhh");
printWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fileWriter!=null) {
try {
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (printWriter!=null){
printWriter.close();
}
}
}
finally總是被執行(不過凡事都有例外) 。
finally遇見如下情況不會執行
- 在前面的代碼中用了System.exit()退出程式。
- finally語句塊中發生了異常。
- 程式所在的線程死亡。
- 關閉CPU。
try-finally可直接使用
finally内部不建議寫return,會覆寫原先的return
try-with-resource
try-with-resource是Java 7中引入的
JAVA 7 提供了更優雅的方式來實作資源的自動釋放,自動釋放的資源需要是實作了 AutoCloseable 接口的類。
public void BufferedWriter() {
final File file = new File("C:/Users/TheBlindM/Desktop/gbk.txt");
try (FileWriter fileWriter = new FileWriter(file);
final PrintWriter printWriter = new PrintWriter(fileWriter);) {
while (true) {
printWriter.println("hhh");
printWriter.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
流程
五.實作機制
異常表
行号
20 public static int throwException() {
21 int x;
22 try {
23 x=1;
24 return x;
25 }catch (Exception e){
26 x=2;
27 return x;
28 }finally {
29 x=3;
30 }
31 }
public static int throwException();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=4, args_size=0
0: iconst_1 //1(int)值入棧。 對應23行 x=1
1: istore_0 //将棧頂int類型值儲存到局部變量0中。
2: iload_0 //從局部變量0中裝載int類型值入棧。 對應24行
3: istore_1
4: iconst_3 //3(int)值入棧。 對應23行 x=1
5: istore_0
6: iload_1 //從局部變量1中裝載int類型值入棧。 值為1
7: ireturn
8: astore_1 // 将棧頂引用類型值儲存到局部變量1中。
9: iconst_2 //2(int)值入棧。 對應26行 x=2
10: istore_0 //将棧頂int類型值儲存到局部變量0中
11: iload_0 //從局部變量0中裝載int類型值入棧。 對應27行
12: istore_2 //
13: iconst_3
14: istore_0 //
15: iload_2
16: ireturn
17: astore_3 //将棧頂引用類型值儲存到局部變量3中。
18: iconst_3 //1(int)值入棧。 對應27行 x=1
19: istore_0
20: aload_3
21: athrow
Exception table:
from to target type
0 4 8 Class java/lang/Exception
0 4 17 any
8 13 17 any
Exception table:異常表
- from 可能會發生異常的起點
- to 可能會發生異常的結束點
- target from to之間發生異常後處理的位置
- type 可以處理的類型
3條異常表對應三條
- 如果try語句塊中出現屬于Exception或其子類的異常,則轉到catch語句處理
- 如果try語句塊中出現不屬于Exception或其子類的異常,則轉到finally語句處理
- 如果catch語句塊中出現異常,則轉到finally語句處理
問題:
1.如果finally中帶return或者catch中帶return,會怎樣?
如果帶return 在位元組碼中會轉化為ireturn(傳回int類型值,傳回棧頂)
六.編寫建議
1.異常應該用于異常的情況下,永遠不要應該用于正常的控制流程
2.對于可恢複的情況使用受檢異常,對于程式設計錯誤使用運作時異常
3. 優先使用标準異常
異常 | 使用場合 |
---|---|
IllegalArgumentException | 參數的值不合适 |
IllegalStateException | 參數的狀态不合适 |
NullPointerException | 在null被禁止的情況下參數值為null |
IndexOutOfBoundsException | 下标越界 |
ConcurrentModificationException | 在禁止并發修改的情況下,對象檢測到并發修改 |
UnsupportedOperationException | 對象不支援客戶請求的方法 |
4.優先捕獲最具體的異常
5.不要記錄并抛出異常
歡迎關注公衆号
參考
深入了解JVM虛拟機
Effective Java
https://www.pdai.tech/md/java/basic/java-basic-x-exception.html