1. 程式人生 > 其它 >try-catch-finally 異常處理的兩種方式

try-catch-finally 異常處理的兩種方式

異常處理

1. 明確什麼是異常 (重點)

2. 能辨識出常見的異常及其含義。 (熟悉+)

3. 理解異常產生的原理 (瞭解)

4. 能處理異常 (重點)

5. 能夠自定義異常型別 (熟悉)

目的

我們發現異常,捕獲異常的目的是要對異常進行補救,而不是列印一下。

什麼是異常?

異常是在程式中導致程式中斷執行的一種指令流。

例如,現在有如下的操作程式碼:

public class ExceptionDemo01{
public static void main(String argsp[]){
int i = 10 ;
int j = 0 ;
System.out.println("============= 計算開始 =============") ;
int temp = i / j ; // 進行除法運算 System.out.println("temp = " + temp) ; System.out.println("============= 計算結束 =============") ; } }; 執行結果: ============= 計算開始 ============= Exception in thread "main" java.lang.ArithmeticException: / by zero at ExceptionDemo01.main(ExceptionDemo01.java:6)

以上的程式碼在“int temp = i / j ;”位置處產生了異常,一旦產生異常之後,異常之後的語句將不再執行了,所以現 在的程式並沒有正確的執行完畢之後就退出了。

那麼,為了保證程式出現異常之後仍然可以正確的執行完畢,所以要採用異常的處理機制。

處理異常

異常處理一般有兩種方式,1.使用catch捕獲異常; 2.使用throws關鍵字在方法宣告時丟擲異常

1.catch捕獲異常

如果要想對異常進行處理,則必須採用標準的處理格式,處理格式語法如下:

try{

// 有可能發生異常的程式碼段

}catch(異常型別1 物件名1){

// 異常的處理操作 異常補救

}catch(異常型別2 物件名2){

// 異常的處理操作 異常補救

} ...

finally{

// 異常的統一出口

System.out.println("這裡的程式碼無論是否出現異常都會執行,一般用於資源回收");

}

在進行異常的處理之後,在異常的處理格式中還有一個finally語句,那麼此語句將作為異常的統一出口,不管是否產生 了異常,最終都要執行此段程式碼。

無論異常是否發生,finally必然執行。讀取檔案,佔用檔案,讀取資料庫等,都在finally中釋放,因為finally必然執行。一般用於資源回收。

try+catch的處理流程

1、 一旦產生異常,則系統會自動產生一個異常類的例項化物件。

2、 那麼,此時如果異常發生在try語句,則會自動找到匹配的catch語句執行,如果沒有在try語句中,則會將異 常丟擲.

3、 所有的catch根據方法的引數匹配異常類的例項化物件,如果匹配成功,則表示由此catch進行處理。

2.throws throw 丟擲異常

在程式中異常的基本處理已經掌握了,但是隨異常一起的還有一個稱為throws關鍵字,此關鍵字主要在方法的宣告上使 用,表示方法中不處理異常,而交給呼叫處處理。

1.throws是函式方法丟擲異常,一般寫在方法的頭部,用來丟擲一些異常,本身不進行解決,拋給方法的呼叫者進行解決(try catch)

格式: 返回值 方法名稱()throws Exception{ }

Integer類: public static int parseInt(String text)throws NumberFormatException

2.throw是語句丟擲異常,出現於函式內部,用來丟擲一個具體異常例項,throw被執行後面的語句不起作用,直接轉入異常處理階段

一般是使用者自定義的RuntimeException執行時異常,然後使用throw丟擲。

 1 public class Demo9 {
 2     public static void main(String[] args) {
 3     }
 4 
 5     /**
 6      * 異常是否丟擲去, 應該站在哪個角度思考?
 7      *
 8      *  如果是因為傳參導致異常 , 應該通過throws將異常丟擲去.
 9      *
10      * @param text
11      * @throws IOException : 因為傳遞的指令不對, 會導致此問題發生(s2=0時)
12      */
13     public static void shutdown(String text) throws IOException {
14         Runtime.getRuntime().exec(text);
15     }
16     /**
17      * 此方法用於求兩個引數的和
18      *  會將兩個引數 轉換為數字 求和
19      * @param s1  字串引數1
20      * @param s2  字串引數2
21      */
22     public static void sum(String s1,String s2){
23         int sum = Integer.parseInt(s1)+Integer.parseInt(s2);
24         System.out.println("和是:"+sum);
25     }
26 }
 1 public class Person {
 2     private String name;
 3     private int age;
 4 
 5     public String getName() {
 6         return name;
 7     }
 8 
 9     public void setName(String name) {
10         this.name = name;
11     }
12 
13     public int getAge() {
14         return age;
15     }
16 
17     public void setAge(int age) {
18         if(age<0 || age>180){
19             RuntimeException e = new RuntimeException("年齡不合理");
20             throw e;
21         }else{
22             this.age = age;
23         }
24 
25     }
26 }

異常體系結構

異常指的是Exception , Exception類, 在Java中存在一個父類Throwable(可能的丟擲)

Throwable存在兩個子類:

1.Error:表示的是錯誤,是JVM發出的錯誤操作,只能儘量避免,無法用程式碼處理。

2.Exception:一般表示所有程式中的錯誤,所以一般在程式中將進行try…catch的處理。

RuntimeExcepion與Exception的區別

RuntimeException是Exception的子類,

catch(Exception e) 就是範圍最大的捕獲異常。如果為了方便,則可以將所有的異常都使用Exception進行捕獲。

所有RuntimeException的子類即為非檢查型異常;Exception的其餘子類都為檢查型異常。所謂“檢查型異常”是指在原始碼例必須顯式地進行捕獲處理,eclipse和idea都是自動編譯的,當我們把程式碼寫完的時候,如果有紅線提示或者錯誤提示,那麼就是檢查異常。也就是說,當你看到某個方法宣告中可能丟擲某個檢查型異常,那麼作為呼叫方必須考慮如何處理這個異常,否則編譯器就是給出錯誤提示。

所謂“非檢查型異常”,也就是執行時異常,編譯的時候不會給錯誤提示,執行的時候有可能出現異常。如: 使用者輸入0作為除數,就會 出現異常。通常是可以通過編碼加以避免的邏輯錯誤,具體根據需要來判斷是否需要捕獲,並不會在編譯期強制要求。例如NullPointerException、ArrayIndexOutOfBoundsException等。也就是說,程式設計師應該通過合理編碼來努力避免程式出現這類異常,或者說程式出現這類異常就是程式設計師的責任。

異常處理常見面試題

1. try-catch-finally 中哪個部分可以省略?

答: catch和finally可以省略其中一個 , catch和finally不能同時省略 注意:格式上允許省略catch塊, 但是發生異常時就不會捕獲異常了,我們在開發中也不會這樣去寫程式碼.

2. try-catch-finally 中,如果 catch 中 return 了,finally 還會執行嗎?

答:finally中的程式碼會執行 詳解:

執行流程:

1. 先計算返回值, 並將返回值儲存起來, 等待返回

2. 執行finally程式碼塊

3. 將之前儲存的返回值, 返回出去;

需注意:

1. 返回值是在finally運算之前就確定了,並且快取了,不管finally對該值做任何的改變,返回的值都不 會改變

2. finally程式碼中不建議包含return,因為程式會在上述的流程中提前退出,也就是說返回的值不是try或 catch中的值

3. 如果在try或catch中停止了JVM,則finally不會執行.例如停電- -, 或通過如下程式碼退出 JVM:System.exit(0)。

try中有return時,finally也會執行,這個return值在finally執行之前的try中已經準備好了,複製備份放入了快取。如果return返回的是基本資料型別,如int,那麼finally中再給int賦值也不會改變return返回的值。如果return返回的是一個物件,那麼複製到快取中的是這個物件的地址,這時在finally中改變這個物件的值時,返回的值就是改變以後的值。

 1 public class Demo7 {
 2     public static void main(String[] args) {
 3         int a = haha();
 4         System.out.println(a);
 5     }
 6     public static int haha(){
 7         int a = 10;
 8         try{
 9             return a;
10         }catch(Exception e){
11 
12         }finally {
13             a = 20;
14         }
15         return 0;
16     }
17     static class Person{
18         int age;
19     }
20 }

以上輸出結果是:10

因為finally執行之前,retrun 的a是10,這個值已經複製到快取中,輸出時,就i時輸出快取中的值。finally再改變a的值也不會被輸出。

 1 public class Demo6 {
 2     public static void main(String[] args) {
 3         Person p = haha();
 4         System.out.println(p.age);
 5     }
 6     public static Person haha(){
 7         Person p = new Person();
 8         try{
 9             p.age = 18;
10             return p;
11         }catch(Exception e){
12             return null;
13         }finally {
14             p.age = 28;
15         }
16     }
17     static class Person{
18         int age;
19     }
20 }

以上輸出結果是:28

try中return的p物件,放到輸出快取中是P物件的地址。finally中改變的是這個地址中的值,所以輸出的值就是改變之後的值。