天天看點

Java 異常從精通到陌生Java 異常從精通到陌生

Java 異常從精通到陌生

一.什麼的異常?

異常(不同于尋常的)指的是在程式運作過程中發生的異常事件,通常是由外部問題(如硬體錯誤、輸入錯誤)所導緻的。在Java等面向對象的程式設計語言中異常屬于對象。

在Java中通過Throwable類的各種子類來描述不同的異常。

二.為什麼使用異常機制

  • 可讀性
  • 可靠性
  • 可維護性

三.Java異常層次結構

Java 異常從精通到陌生Java 異常從精通到陌生

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();
	}

}
           

流程

Java 異常從精通到陌生Java 異常從精通到陌生

五.實作機制

異常表

行号
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.不要記錄并抛出異常

歡迎關注公衆号

Java 異常從精通到陌生Java 異常從精通到陌生

參考

深入了解JVM虛拟機

Effective Java

https://www.pdai.tech/md/java/basic/java-basic-x-exception.html