Java中的異常處理try catch(第八周課堂示例總結)


異常處理

使用Java異常處理機制:

把可能會發生錯誤的代碼放進try語句塊中。

當程序檢測到出現了一個錯誤時會拋出一個異常對象。

異常處理代碼會捕獲並處理這個錯誤。

catch語句塊中的代碼用於處理錯誤。

當異常發生時,程序控制流程由try語句塊跳轉到catch語句塊。

不管是否有異常發生,finally語句塊中的語句始終保證被執行。

如果沒有提供合適的異常處理代碼,JVM將會結束掉整個應用程序。

 異常分類:

Throwable類有兩個直接子類:

Exception:出現的問題是可以被捕獲的;

Error:系統錯誤,通常由JVM處理。

可捕獲的異常又可以分為兩類:

(1)Check異常:直接派生自Exception的異常類,必須被捕獲或再次聲明拋出

(2)Runtime異常:派生自RuntimeException的異常類。使用throw語句可以隨時拋出這種異常對象: throw new ArithmeticException(…);

JDK1.4 以上提供了assert語句,允許程序在運行期間判斷某個條件是否滿足,不滿足時,拋出AssertionError,例如:

異常的“多態”特性

可以有多個catch語句塊,每個代碼塊捕獲一種異常。在某個try塊后有兩個不同的catch 塊捕獲兩個相同類型的異常是語法錯誤。

使用catch語句,只能捕獲Exception類及其子類的對象。因此,一個捕獲Exception對象的catch語句塊可以捕獲所有“可捕獲”的異常。

將catch(Exception e)放在別的catch塊前面會使這些catch塊都不執行,因為Java不會編譯這些catch塊。

“finally”的功用

資源泄露:當一個資源不再被某應用程序使用,但此程序並未向系統聲明不再使用此資源時發生這種情況

finally語句塊主要用於解決資源泄露問題,它位於catch語句塊之后,JVM保證它們一定執行。

注意:finally語句塊中也可能發生異常,如果這種情況發生,先前的異常被放棄。

動手動腦:多層的異常捕獲

比較兩個代碼的區別:

CatchWho1.java 

 1 public class CatchWho { 
 2     public static void main(String[] args) { 
 3         try {
 4                 try {
 5                     throw new ArrayIndexOutOfBoundsException(); 
 6                 } 
 7                 catch(ArrayIndexOutOfBoundsException e) { 
 8                        System.out.println(  "ArrayIndexOutOfBoundsException" +  "/內層try-catch"); 
 9                 }
10             throw new ArithmeticException(); 
11         }
12         catch(ArithmeticException e) { 
13             System.out.println("發生ArithmeticException"); 
14         } 
15         catch(ArrayIndexOutOfBoundsException e) { 
16            System.out.println(  "ArrayIndexOutOfBoundsException" + "/外層try-catch"); 
17         } 
18     } 
19 }

結果:

catchwho2.java

 1 public class CatchWho2 { 
 2     public static void main(String[] args) { 
 3         try {
 4                 try { 
 5                     throw new ArrayIndexOutOfBoundsException(); 
 6                 } 
 7                 catch(ArithmeticException e) { 
 8                     System.out.println( "ArrayIndexOutOfBoundsException" + "/內層try-catch"); 
 9                 }
10             throw new ArithmeticException(); 
11         } 
12         catch(ArithmeticException e) { 
13             System.out.println("發生ArithmeticException"); 
14         } 
15         catch(ArrayIndexOutOfBoundsException e) { 
16             System.out.println( "ArrayIndexOutOfBoundsException" + "/外層try-catch"); 
17         } 
18     } 
19 }

結果:

 分析:catchwho1按照內外層的try catch代碼塊一步一步執行

catchwho2結果的原因是內存try里的異常並沒有被catch(ArithmeticException e)捕獲到,故該字段異常,不執行此try catch塊下的其他內容,而是此異常的ArrayIndexOutOfBoundsException()對象被外層的catch(ArrayIndexOutOfBoundsException e)捕獲,打印出相應結果。

辨析:finally語句塊一定會執行嗎?

 1 public class SystemExitAndFinally {
 2     public static void main(String[] args)
 3     {
 4         try{
 5             System.out.println("in main");
 6             throw new Exception("Exception is thrown in main");
 7                     //System.exit(0);
 8         }
 9         catch(Exception e){
10             System.out.println(e.getMessage());
11             System.exit(0);
12         }
13         finally{
14             System.out.println("in finally");
15         }
16     }
17 }

結果:

 結論:在exit(0)下, finally里的語句塊不會執行。

特別注意: 當有多層嵌套的finally時,異常在不同的層次拋出 ,在不同的位置拋出,可能會導致不同的finally語句塊執行順序。

如何跟蹤異常的傳播路徑?

當程序中出現異常時,JVM會依據方法調用順序依次查找有關的錯誤處理程序。

可使用printStackTrace 和 getMessage方法了解異常發生的情況: printStackTrace:打印方法調用堆棧。

每個Throwable類的對象都有一個getMessage方法,它返回一個字串,這個字串是在Exception構造函數中傳入的,通常讓這一字串包含特定異常的相關信息。

 1 // UsingExceptions.java
 2 // Demonstrating the getMessage and printStackTrace
 3 // methods inherited into all exception classes.
 4 public class PrintExceptionStack {
 5    public static void main( String args[] ){
 6       try {
 7          method1();
 8       }
 9       catch ( Exception e ) {
10          System.err.println( e.getMessage() + "\n" );
11          e.printStackTrace();
12       }
13    }
14    public static void method1() throws Exception {
15       method2();
16    }
17    public static void method2() throws Exception{
18       method3();
19    }
20    public static void method3() throws Exception{
21       throw new Exception( "Exception thrown in method3" );
22    }
23 }

輸出結果:

 

 受控與不受控的異常

throws語句:throws語句表明某方法中可能出現某種(或多種)異常,但它自己不能處理這些異常,而需要由調用者來處理。 當一個方法包含throws子句時,需要在調用此方法的代碼中使用try/catch/finally進行捕獲,或者是重新對其進行聲明,否則編譯時報錯。

throws語句中聲明的異常稱為受控(checked)的異常,通常直接派生自Exception類。

RuntimeException(其基類為Exception) 和Error(基類為Throwable)稱為非受控的異常。這種異常不用在throws語句中聲明。

 1 import java.io.*; 
 2  
 3 public class CheckedExceptionDemo { 
 4     public static void main(String[] args)  { 
 5         try { 
 6             BufferedReader buf = new BufferedReader( 
 7                 new InputStreamReader(System.in));    //拋出受控的異常
 8             System.out.print("請輸入整數: "); 
 9             int input = Integer.parseInt(buf.readLine()); //有可能引發運行時異常
10             System.out.println("input x 10 = " + (input*10)); 
11       } 
12         //以下異常處理語句塊是必須的,否則無法通過編譯
13         catch(IOException e) { 
14             System.out.println("I/O錯誤"); 
15         } 
16         //以下異常處理語句塊可以省略,不影響編譯,但在運行時出錯
17         catch(NumberFormatException e) { 
18             System.out.println("輸入必須為整數"); 
19         }
20     } 
21 }

一個方法可以聲明拋出多個異常:    int g(float h) throws OneException,TwoException { …… }

 1 import java.io.*;
 2 public class ThrowMultiExceptionsDemo { 
 3     public static void main(String[] args) { 
 4       try { 
 5             throwsTest(); 
 6        } 
 7         catch(IOException e) { 
 8             System.out.println("捕捉異常"); 
 9         }
10     }
11     private static void throwsTest()  throws ArithmeticException,IOException { 
12         System.out.println("這只是一個測試"); 
13         // 程序處理過程假設發生異常
14         throw new IOException(); 
15         //throw new ArithmeticException(); 
16     } 
17 }

在有繼承關系中,一個子類的throws子句拋出的異常,不能是其基類同名方法拋出的異常對象的父類。

自定義異常與異常處理鏈

介紹一種被廣泛使用的異常處理方法——通過自定義異常類捕獲並處理業務邏輯錯誤 。

 1 class MyException extends Exception{
 2     public MyException(String Message) {
 3         super(Message);
 4     }
 5     public MyException(String message, Throwable cause) {
 6         super(message, cause);
 7     }
 8      public MyException(Throwable cause) {
 9         super(cause);
10     }
11 }
12 public class ExceptionLinkInRealWorld {
13    public static void main(String args[]){
14       try {
15          throwExceptionMethod();  //有可能拋出異常的方法調用
16       }
17       catch ( MyException e ){
18          System.err.println( e.getMessage() +"--1");
19          System.err.println(e.getCause().getMessage()+"--2");
20       }
21       catch ( Exception e ){
22          System.err.println("Exception handled in main--3" );
23       }
24       doesNotThrowException(); //不拋出異常的方法調用
25    }
26    public static void throwExceptionMethod() throws MyException{
27       try {
28          System.out.println( "Method throwException--4" );
29          throw new Exception("系統運行時引發的特定的異--W");  // 產生了一個特定的異常
30       }
31       catch( Exception e ){
32          System.err.println("Exception handled in method throwException--5" );
33          //轉換為一個自定義異常,再拋出
34          throw new MyException("在方法執行時出現異常-W",e);
35       }
36       finally {
37          System.err.println("Finally executed in throwException--6" );
38       }
39       // any code here would not be reached
40    }
41    public static void doesNotThrowException()
42    {
43       try {
44          System.out.println( "Method doesNotThrowException--7" );
45       }
46       catch( Exception e ){
47          System.err.println( e.toString() );
48       }
49       finally {
50          System.err.println("Finally executed in doesNotThrowException--8" );
51       }
52       System.out.println("End of method doesNotThrowException--9" );
53    }
54 }
55 
56 //45
ExceptionLinkInRealWorld.java

結果:

在實際開發中,可以參照ExceptionLinkInRealWorld.java 示例的做法,定義一些與業務邏輯相關的自定義異常類,供上層代碼進行捕獲,從而能更精確地反映系統真實運行情況並及時進行處理。

關於開發中異常處理的建議

在中間層組件中拋出異常,在界面層組件中捕獲異常,在底層組件中捕獲JVM拋出的“只有程序員能看懂的”異常,轉換為中間層的業務邏輯異常,再由界面層捕獲以提供有意義的信息。

自身能夠處理的異常,不要再向外界拋出。

盡可能地在靠近異常發生的地方捕獲並處理異常。

盡可能地捕獲最具體的異常類型,不要在中間層用 catch(Exception)“吃掉”所有異常。

在開發階段捕獲並顯示所有異常信息,發布階段要移除部分代碼,以避免“過於專業”的異常信息困擾用戶,特別地,系統發布之后,不要將服務端異常的詳細信息發給客戶端,以免被黑客利用。


免責聲明!

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



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