Java 異常處理 之 異常處理機制一:try-catch-finally


一、Java 異常處理

  編寫程序時,要在出現可能出現錯誤的時候加上檢測的代碼,如判斷分母為0,數據為空,過多的 if-else分支導致程序代碼加長,臃腫,可讀性差,因此采用異常處理機制。

  Java采用的異常處理機制,是將異常處理的程序代碼集中在一起,與正常的程序代碼分開,使得程序簡潔、優雅, 並易於維護。

  

二、異常處理:抓拋模型

  1、拋出

    Java 程序的執行過程中出現異常,會生成一個異常類對象,該異常對象將被提交給 Java 運行時系統,這個過程稱為拋出(throw)異常。一旦拋出對象以后,其后的代碼就不再執行。

  2、捕獲、“抓”

    可以理解為異常的處理方式:① try-catch-finally;  ② throws;

  3、異常對象的生成

    (1)由虛擬機自動生成:程序運行過程中,虛擬機檢測到程序發生了問題,如果在當前代碼中沒有找到相應的處理程序,就會在后台自動創建一個對應異常類的實例對象並拋出——自動拋出;

    (2)由開發人員手動創建:Exception exception = new ClassCastException;——創建好的異常對象不拋出對程序沒有任何影響,和創建一個普通對象一樣;

  4、處理異常過程

    (1)當程序運行到某一句時,發生了異常,那么程序會先停下來;

    (2)程序會在這句代碼處,查看原因,生成一個合理“異常對象”,然后“拋”出;

    (3)JVM 會檢測這句代碼的外圍,是否有 try...catch 結構,可以“捕獲”它;

    (4)如果可以捕獲,那么程序在處理完異常后,繼續下面的運行,不會崩潰;

    (5)如果不能捕獲,那么會把這個異常繼續拋給“上級”,如果“上級”能處理,那么程序從“上級"處理完的代碼后面繼續運行;

    (6) 如果上級也不能處理,那么繼續往上拋,一直到達JVM,那么就“崩潰”;

    

     ① 如果一個方法內拋出異常,該異常對象會被拋給調用者方法中處理。 如果異常沒有在調用者方法中處理, 它繼續被拋給這個調
方法的上層方法。 這個過程將一直繼續下去, 直到異常被處理。這一過程稱為捕獲(catch)異常

    ② 如果一個異常回到main()方法, 並且main()也不處理, 則程序運行終止。

    ③ 程序員通常只能處理Exception, 而對Error無能為力。

  5、不捕獲異常時的情況

    (1)如果捕獲的是 RuntimeException 類或它的子類,這些類的異常特點是:即使沒有使用 try 和 catch 捕獲,Java 自己也能捕獲,並且編譯通過,(但運行時會發生異常使得程序運行終止)

    (2)如果拋出的異常是 IOException 等類型的非運行時異常,則必須捕獲,否則編譯錯誤,也就是說,必須處理編譯時異常,將異常進行捕捉,轉化為運行時異常;

三、處理機制一:try...catch...finally

  1、try

    捕獲異常的第一步是用 try{} 語句塊選定捕獲異常的范圍,將可能出現的異常的代碼放在 try 語句塊中;

  2、catch(ExceptionType e)

    在 catch 語句塊中是對 異常對象 進行處理的代碼。每個 try 語句塊可以伴隨一個或多個 catch 語句,用於處理可能產生的不同類型的異常對象。

    如果明確知道產生的是何種異常,可以用該異常類作為 catch 的參數;也可以用其父類作為 catch 的參數;

比 如 : 可 以 用 ArithmeticException 類 作 為 參 數 的 地 方 , 就 可 以 用RuntimeException類作為參數, 或者用所有異常的父類Exception類作為參數。但不能是與ArithmeticException類無關的異常, 如NullPointerExceptioncatch中的語句將不會執行) 。

 

  3、捕獲異常的有關信息

    與其他對象一樣,可以訪問一個異常對象的成員變量或調用它的方法。

getMessage() 獲取異常信息,返回字符串;
printStackTrace() 獲取異常類名和異常信息,以及異常出現在程序中的位置。返回值void。

    

  4、finally

  (1)捕獲異常的最后一步是通過 finally 語句為異常處理提供一個統一的出口,使得在控制流轉到程序的其他部分以前,能夠對程序的狀態作統一的管理;

  (2)不論在 try 代碼塊中是否發生了異常事件,catch 語句是否執行,catch 語句是否有異常,catch 語句中是否有 return,finally 塊中的語句都會被執行。

  (3)finally 語句和 catch 語句是任選的;

    

四、捕獲異常:try...catch...finally

  1、語法格式

try{ ...... //可能產生異常的代碼
 } catch( ExceptionName1 e ){ ...... //當產生ExceptionName1型異常時的處置措施
 } catch( ExceptionName2 e ){ ...... //當產生ExceptionName2型異常時的處置措施
 } [ finally{ ...... //無論是否發生異常, 都無條件執行的語句
    } ]        

      try:該代碼塊中編寫可能產生異常的代碼

   catch:用來進行某種異常的捕獲,實現對捕獲到的異常進行處理。

    

  注意

    (1)trycatch都不能單獨使用,必須連用。 

    (2)try中可能會拋出多個異常對象,那么就可以使用多個catch來處理這些異常對象

    (3)如果try中產生了異常,那么就會執行 catch 中的異常處理邏輯,執行完畢 catch 中的處理邏輯,繼續執行try...catch之后的代碼;

        如果 catch 無法捕獲 try 中發生的異常,那么就會導致當前方法結束,並把異常對象拋出給調用者,如果調用者可以處理,那么從調用者處理代碼的后面繼續運行,否則繼續向上拋出,最終達到 JVM;

        如果try中沒有產生異常,那么就不會執行catch中異常的處理邏輯,執行完try中的代碼,繼續執行try...catch之后的代碼

  2、多個 catch 分析,如何匹配和執行的?

    從上到下依次判斷,一旦有一個滿足了,后面就不看了。

    建議:如果多個catch中的異常類型有大小包含關系,那么小的在上,大的在下,如果沒有大小包含關系,順序隨意。

    Demo:

 1 public class TryCatchDemo { 2     public static void main(String[] args) { 3         try {// 當產生異常時,必須有處理方式。要么捕獲,要么聲明。
 4             read("b.txt"); 5         } catch (FileNotFoundException e) {// 括號中需要定義什么呢?
 6             //try中拋出的是什么異常,在括號中就定義什么異常類型
 7 System.out.println(e); 8 } 9         System.out.println("over"); 10 } 11      /* 12 當前的這個方法中 有異常 有編譯期異常 13 */
14     public static void read(String path) throws FileNotFoundException { 15         if (!path.equals("a.txt")) {//如果不是 a.txt這個文件
16             // 我假設 如果不是 a.txt 認為 該文件不存在 是一個錯誤 也就是異常 throw
17             throw new FileNotFoundException("文件不存在"); 18 } 19 } 20 }  

 

  擴展:Throwable類中定義了一些獲取異常信息的方法(異常對象常用的方法)

public String getMessage() :獲取異常的簡短描述信息,原因(提示給用戶的時候,就提示錯誤原因)
public String toString() :獲取異常的類型和異常詳細描述信息(不用)。
public void printStackTrace() :打印異常的跟蹤棧信息並輸出到控制台,JVM打印異常對象,默認此方法,打印的異常信息是最全面的

  Tips包含了異常的類型,異常的原因,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace 

  Demo:

System.out.println(e.getMessage());
System.out.println(e.toString());
System.out.println(e);

 

  3、finally 代碼塊

       finally有一些特定的代碼無論異常是否發生,都需要執行。另外,因為異常會引發程序跳轉,導致有些語句執行不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執行的。

    必須執行的代碼try語句塊中打開了一些物理資源(磁盤文件/網絡連接/數據庫連接等),都得在使用完之后,最終關閉打開的資源或斷開連接等操作。

  語法格式:

     try{
            可能產生異常的代碼
        }catch(定義一個異常的變量,用來接收try中拋出的異常對象){
            異常的處理邏輯,異常異常對象之后,怎么處理異常對象
            //記錄日志/打印異常信息/繼續拋出異常
        }
        ...
        catch(異常類名 變量名){

        }finally{
            無論是否出現異常都會執行
        }

    注意

     (1)finally不能單獨使用,必須和try一起使用

     (2)finally一般用於資源釋放(資源回收),無論程序是否出現異常,最后都要資源釋放(IO)

    Demo:

 1 public static void main(String[] args) { 2         try { 3             //可能會產生異常的代碼
 4             readFile("c:\\a.tx"); 5         } catch (IOException e) { 6             //異常的處理邏輯
 7 e.printStackTrace(); 8         } finally { 9             //無論是否出現異常,都會執行
10             System.out.println("資源釋放"); 11 } 12 } 13 
14     /* 15 如果傳遞的路徑,不是.txt結尾 16 那么就拋出IO異常對象,告知方法的調用者,文件的后綴名不對 17 18 */
19     public static void readFile(String fileName) throws IOException { 20 
21         if(!fileName.endsWith(".txt")){ 22             throw new IOException("文件的后綴名不對"); 23 } 24 
25         System.out.println("路徑沒有問題,讀取文件"); 26     }

 

    Tips當只有在 try 或者 catch 中調用退出 JVM 的相關方法(System.exit(0);,此時finally才不會執行,否則finally永遠會執行。

  4、

五、finally 與 return 混用

  (1)不管try中是否發生異常,也不管catch是否可以捕獲異常,也無論try或catch中是否有return。 finally中的代碼都必須執行;

  (2)如果finally中有return,就從finally塊的的return回去。

  (3)如果finally中沒有return,那么先把try或catch中該執行的執行完(包括把返回值的結果放到要帶回調用處的操作數棧的位置),在return結束當前方法之前,先走一下finally,然后回去結束當前方法;

  結論:如果 finally 中沒有 return,finally 中的代碼不影響返回值;

  Demo1:

 1 public static void main(String[] args) { 2     String str = getNum(1); 3 System.out.println(str); 4 } 5     
 6 public static String getNum(int a){ 7     try{ 8        System.out.println(a/0); 9        if(a > 0){ 10             return "正數"; 11        }else if(a < 0){ 12             return "負數"; 13        }else{ 14             return "零"; 15 } 16     }catch(Exception e){ 17         return "異常"; 18     }finally{ 19         return "最終"; 20 } 21 }

    運行結果:

最終

 

  Demo2:

 1 public static void main(String[] args) { 2    String str = getNum(1); 3 System.out.println(str); 4 } 5     
 6 public static String getNum(int a){ 7     try{ 8        System.out.println(a/0); 9        if(a > 0){ 10             return "正數"; 11        }else if(a < 0){ 12             return "負數"; 13        }else{ 14             return "零"; 15 } 16     }catch(Exception e){ 17         System.out.println("exception"); 18         return "異常"; 19     }finally{ 20         System.out.println("finally"); 21 } 22 }

  運行結果:

exception

 finally

 異常

 

  Demo3:

 1   public static void main(String[] args) { 2         int num = getNum(4); 3         System.out.println(num);//0
 4 } 5     
 6     public static int getNum(int a){ 7         int result = 10; 8         try{ 9             System.out.println(a/0); 10             if(a > 0){ 11                 result = 20; 12                 return result; 13             }else if(a < 0){ 14                 result = -20; 15                 return result; 16             }else{ 17                 return result; 18 } 19         }catch(Exception e){ 20             System.out.println("exception"); 21             result = 0; 22             return result;     //從這里返回,result=0
23         }finally{ 24             result = 30; 25             System.out.println("finally"); 26 // return result;//如果有這句,結果就變成30
27 } 28     }

  運行結果:

exception

finally

0

 

  Demo4:

 1 public class Test { 2 { 3         System.out.println("b"); 4 } 5     static{ 6         System.out.println("a"); 7 } 8 TestExer4(){ 9         System.out.println("c"); 10 } 11     public static String getOut(){ 12         try{ 13             return "1"; 14         }catch(Exception e){ 15             return "2"; 16         }finally{ 17             return "3"; 18 } 19 } 20     public static void main(String[] args) { 21         System.out.println(getOut());//3
22 } 23 }

  運行結果:

a

3

 


免責聲明!

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



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