1. 程式人生 > >JAVA:異常及異常處理

JAVA:異常及異常處理

1.異常的概念

  • 異常是指程式執行期間出現的錯誤,而非編譯時的語法錯誤。例如,程式要開啟不存在的資料夾、網路連線中斷、運算元越界、裝載一個不存在的類、算數異常等。

  • 使用異常的目的在於通過使用少於目前數量的程式碼來簡化大型、可靠的程式的生成,並且通過這種方式可以使你更加自信:你的應用沒有未處理的錯誤。——《JAVA程式設計思想》如是說。

  • 補充:
    這裡寫圖片描述
  • 示例1:
public class  TestException
{
    public static void main(String[] args) 
    {
        int array[] = {1, 2, 3};
        System.out
.println("array[5]=" + array[5]); } }
  • 編譯,執行:
D:\JavaProject\demo14>javac TestException.java

D:\JavaProject\demo14>java TestException
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
        at TestException.main(TestException.java:6)
  • 出現了“陣列索引越界異常”,ArrayIndexOutOfBoundsException。在Java中,會嚴格檢查陣列的長度的,即在程式中,執行時不能出現數組越界的索引。

  • 示例2:

public class  TestException
{
    public static void main(String[] args) 
    {
        int a = 2/0;
    }
}
  • 編譯,執行:
D:\JavaProject\demo14>javac TestException.java

D:\JavaProject\demo14>java TestException
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at TestException.main
(TestException.java:5)
  • 出現了算數異常。執行打印出的異常資訊就是“錯誤的堆疊資訊”。

  • 錯誤堆疊資訊:此錯誤可能是上一個錯誤導致的,上一個錯誤又可能是另外一個錯誤引起的,到底是由哪一個錯誤引起的,把這些錯誤資訊都打印出來,為程式設計師提供了除錯資訊,方便程式設計師進行錯誤追蹤和除錯。

2.異常的分類

這裡寫圖片描述
這裡寫圖片描述

3.捕獲異常及處理

3.0異常處理

這裡寫圖片描述

  • 補充:對於RuntimeException類的子類exception,我們可以也可以不使用try-catch語句來捕獲異常。對於除了RuntimeException類的子類exception之外的exception,我們都必須需要使用try-catch語句來捕獲異常,例如ArrayIndexOutOfBoundsException異常類。
  • 對於異常,當前環境沒有足夠的資訊來解決這個問題,所以就把這個問題提交到一個更高級別的環境中,一直到main()方法,在這裡將作出正確的決定。

這裡寫圖片描述

3.1 呼叫丟擲異常的方法使用try{}catch(){}語句

  • try{}catch(){}語句:當try程式碼中的程式發生了異常,系統將這個異常發生的程式碼行號、類別資訊封裝到一個物件e中,並將這個物件傳遞給catch程式碼塊。
  • 每個try語句必須有一個或多個catch語句,try程式碼塊與catch程式碼塊及finally程式碼塊之間不能有其他語句存在。
    這裡寫圖片描述

  • finally語句
    (1)在try-catch語句後,還可以有一個finally語句,finally語句中的程式碼不管是異常是否被捕獲總是要執行的。
    (2)finally中的程式碼塊不能被執行的唯一情況是:在被保護程式碼塊執行了System.exit(0);語句。
    (3)finally語句的其他用法參見:《Java程式設計思想》第12.8節,或者我的下一篇博文:JAVA——finally塊中的程式碼什麼時候被執行、執行的效果是什麼?

  • 示例3:
import java.io.*;
public class  TestException
{
    public static void main(String[] args) 
    {
        FileInputStream fis = null;
        fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");/*myfile.txt裡面的內容是hello world!*/
        int b = fis.read();
        while(b != -1)
        {
            System.out.println((char)b);
            b = fis.read();
        }
        fis.close();
    }
}
  • 編譯,執行:可以發現,存在異常沒有進行捕獲和處理(丟擲)。
D:\JavaProject\demo14>javac TestException.java
TestException.java:7: 錯誤: 未報告的異常錯誤FileNotFoundException; 必須對其進行
捕獲或宣告以便丟擲
                fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt")
;
                      ^
TestException.java:8: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
                int b = fis.read();
                                ^
TestException.java:12: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
                        b = fis.read();
                                    ^
TestException.java:14: 錯誤: 未報告的異常錯誤IOException; 必須對其進行捕獲或宣告
以便丟擲
                fis.close();
                         ^
4 個錯誤
  • 檢視jdk文件:
    (1)FileInputStream類有三個構造方法,此處呼叫的構造方法如下圖,可以看到該構造方法丟擲了一種沒找到目標檔案的異常類。因此,我們在呼叫該方法時,必須要使用try-catch語句進行捕獲異常。
  • 若一個方法名後寫明瞭throws時,呼叫該方法時必須使用try-catch語句進行捕獲異常。當所丟擲的異常類是RuntimeException的子類時,可以不對其進行try-catch。

  • 這裡寫圖片描述
    這裡寫圖片描述

  • 方法close()和方法read()都會丟擲異常:

  • 這裡寫圖片描述
    這裡寫圖片描述

  • 示例4:

import java.io.*;
public class  TestException
{
    public static void main(String[] args) 
    {
        FileInputStream fis = null;
        try{
            fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
            int b = fis.read();
            while(b != -1){
               System.out.print((char)b);
               b = fis.read();
            }
        }catch (FileNotFoundException fe){
            fe.printStackTrace();
        }catch (IOException ioe){
            ioe.printStackTrace();
        }finally{
            try{
                fis.close();
            }catch (IOException ioe){
                ioe.printStackTrace();
            }
        }
    }
}
  • 編譯,執行:輸出hello world!
D:\JavaProject\demo14>javac TestException.java

D:\JavaProject\demo14>java TestException
hello world!

3.2 宣告方法時丟擲異常:throws SomeException

  • 如果將“示例4”的部分程式碼寫成一個方法:因為在這個func方法中,throws丟擲了兩個異常:FileNotFoundException 、 IOException。因此,我們在使用該方法時,就必須使用try-catch語句進行捕捉和處理。
  • 在宣告時,所丟擲的異常是方法體中可能存在的所有異常類。而FileNotFoundException 是IOException的子類,所以在宣告方法時,直接丟擲IOException類異常即可。但是為了直觀,程式的可讀性,還是建議把所有可能的異常類均完整的寫出來。
  • 而在使用該方法時,FileNotFoundException 是IOException的子類,可以直接建立父類的異常物件IOException即可。

  • 示例5:

import java.io.*;
public class  TestException
{
    public static void main(String[] args) {
        try{
            TestException te = new TestException();
            te.func();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    void func() throws FileNotFoundException , IOException {
        FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
        int b = fis.read();
        while(b != -1){
           System.out.print((char)b);
           b = fis.read();
        }
        fis.close();
    }
}
  • output:
D:\JavaProject\demo14>javac TestException.java

D:\JavaProject\demo14>java TestException
hello world!
  • 當使用函式呼叫方法func()時,func丟擲的異常不是Runtime異常,而是必須捕捉的異常,因此在呼叫時必須寫try-catch,並進行處理。見示例6。
  • 如果捕捉到這周異常後,也不知道怎麼處理,那麼繼續將這些異常給丟擲(在函式名後throws+要丟擲的異常),這時直接呼叫它即可,不需要try-catch語句。只是丟擲父類的異常IOException即可。見示例7。

  • 示例6:

import java.io.*;
public class  TestException
{
    public static void main(String[] args) {
        TestException te = new TestException();
        te.f();
    }

    void func() throws FileNotFoundException , IOException {
        FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
        int b = fis.read();
        while(b != -1){
           System.out.print((char)b);
           b = fis.read();
        }
        fis.close();
    }

    void f() 
    {
        try{
            func();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
  • 示例7:
import java.io.*;
public class  TestException
{
    public static void main(String[] args) {
        try{
            TestException te = new TestException();
            te.f();
        }catch (IOException e){
            e.printStackTrace();
        }
    }

    void func() throws FileNotFoundException , IOException {
        FileInputStream fis = new FileInputStream("D:\\JavaProject\\demo14\\myfile.txt");
        int b = fis.read();
        while(b != -1){
           System.out.print((char)b);
           b = fis.read();
        }
        fis.close();
    }

    void f() throws IOException{
           func();
    }
}

3.3 手動的構造並丟擲異常物件

  • 遇到異常時,遇到throws時,可自動的往外丟擲異常,我們不再去管它了。而還有一種異常,就必須自己手動的往外拋。
  • 拋的格式:throw + 要丟擲的異常物件。方法定義時,指明要丟擲異常的類。
  • 示例8:其中,可以指定異常資訊,如”被除數為0“,利用getMassage()方法就可獲得這個資訊。當丟擲new ArithmeticException(“被除數為0”);以後,這句後面的語句將不再執行。
void m(int i) throws ArithmeticException {
        if(i==0) 
            throw new ArithmeticException("被除數為0");
    }

4.使用自定義異常

-這裡寫圖片描述
這裡寫圖片描述
這裡寫圖片描述

  • 注意:重寫方法需要丟擲與原方法所丟擲異常型別一致的異常,或那些異常的字跡,或不丟擲異常。
  • 這裡寫圖片描述