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中改變的是這個地址中的值,所以輸出的值就是改變之后的值。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM