java-異常

異常簡介

異常指阻止當前方法繼續執行的問題,如:文件找不到、網絡連接失敗、非法參數等。發現異常的理想時期是編譯階段,然而編譯期間.不能找出所有的異常,余下的問題須在運行期間.
java中的異常分為可查異常不可查異常

  1. 可查異常
    即編譯時異常,指編譯器在編譯時可以發現的錯誤,程序在運行時很容易出現的異常狀況,這些異??梢灶A計,所以在編譯階段就必須手動進行捕捉處理,即要么用try-catch語句捕獲它,要么用throws子句聲明拋出,否則編譯無法通過。如IOException、SQLException以及用戶自定義的Exception異常
  2. 不可查異常
    不可查異常包括運行時異常(runtimeException)和錯誤(error),他們都是在程序運行時出現的。異常和錯誤的區別:異常能被程序本身可以處理,錯誤是無法處理
    運行時異常(runtimeException)指的是程序在運行時才會出現的錯誤,由程序員自己分析代碼決定是否用try...catch進行捕捉處理。如nullpointerException,classcastException,indexoutofboundsException。
    錯誤(error),是程序無法處理的錯誤,表示運行應用程序中較嚴重問題,如系統崩潰,虛擬機錯誤,動態連接失敗等。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時JVM(Java虛擬機)出現的問題。例如,Java虛擬機運行錯誤(VirtualMachineError),當JVM不再有繼續執行操作所需的內存資源時,將出現OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。這些錯誤表示故障發生于虛擬機自身、或者發生在虛擬機試圖執行應用時,如Java虛擬機運行錯誤(VirtualMachineError)、類定義錯(NoClassDefFoundError)等。這些錯誤是不可查的,即不需要捕獲和處理,因為它們在應用程序的控制和處理能力之外,而且絕大多數是程序運行時不允許出現的狀況。對于設計合理的應用程序來說,即使確實發生了錯誤,本質上也不應該試圖去處理它所引起的異常狀況。
    Java異常類層次結構圖:

從上圖可以看出Java通過API中Throwable類的眾多子類描述各種不同的異常。因而,Java異常都是對象,是Throwable子類的實例.
在Java中,所有的異常都有一個共同的祖先Throwable(可拋出)。Throwable指定代碼中可用異常傳播機制通過Java應用程序傳輸的任何問題的共性。

異常處理機制

當異常發生時,將使用new在堆上創建一個異常對象,對于這個異常對象,有兩種處理方式.
1.使用throw關鍵字將異常對象拋出,則當前執行路徑被終止,異常處理機制將在其他地方尋找catch塊對異常進行處理.
2.使用try...catch在當前邏輯中就進行捕獲處理.

throws 和throw

  1. throws: 一個方法在聲明時可以使用throws關鍵字聲明可能會產生的若干異常。
  2. throw: 拋出異常,并退出當前方法或作用域。

用throws聲明要拋出的異常,實際可以不拋出。而用throw拋出的異常也可以不聲明。不過Java鼓勵程序員把可能會拋出的異常提前聲明,這是一種優雅的做法。

自定義異常

Java的異常體系不可能包括所有的異常情況,所以可以自己定義異常類來表示程序中可能會遇到的特定問題。

public class MyException extends RuntimeException {
    public MyException() {
    }
public MyException(String message) {
        super(message);
    }
}

在 MyException 這個自定義異常中,定義了兩個構造器。一個是默認構造器,一個接收一個字符串作為參數。在第二個構造器中,可以看出調用了基類構造器,所傳字符串可以通過getMessage()方法獲取。

public class ExceptionTest {
    public static void f(){
        System.out.println("Throwing Exception from f()");
        throw new MyException();
    }

    public static void g(){
        System.out.println("Throwing Exception from g()");
        throw new MyException("Originated in g()");
    }


    public static void main(String[] argv) throws Exception {
        try{
            f();
        }catch(MyException e){
            System.out.println(e.getMessage());
            e.printStackTrace(System.out);
        }
    }
}

在main函數中調用g(),運行結果如下



可以總結出以下兩個函數:

  1. getMessage():獲取一些描述性信息
  2. printStackTrace():從方法調用出到異常拋出處的方法調用序列

重新拋出異常

有時希望把捕獲的異常重新拋出,在catch中已經得到了對當前異常對象的引用,可以將其重新拋出。

public class ExceptionTest {

    public static void g() {
        throw new MyException("Originated in g()");
    }

    public static void h() {
        try {
            g();
        } catch (MyException e) {
            System.out.println("An Exception was thrown from g()");
            throw e;
        }
    }

    public static void k() throws Exception {
        try {
            g();
        } catch (MyException e) {
            System.out.println("An Exception was thrown from g()");
            throw (Exception) e.fillInStackTrace();
        }
    }


    public static void main(String[] argv) throws Exception {
        try {
            h();
        } catch (MyException e) {
            System.out.println(e.getMessage());
            e.printStackTrace(System.out);
        }
        System.out.println();

        try {
            k();
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace(System.out);
        }
    }
}

從運行結果可以看出,如果只是將異常拋出,那么printStackTrace()顯示的仍是原來拋出點的調用棧信息,并非重新拋出點的信息,若想更新信息,可以調用
fillInStackTrace()方法,它通過把當前調用棧信息填入原來那個異常對象而建立。這樣調用fillInStackTrace()的那一行就會新的異常發生點。

使用finally清理

在java中finally的存在并不是為了釋放內存資源,因為java有垃圾回收機制,因此需要java釋放的資源主要是:已經打開的文件或網絡連接等。
在try中無論有沒有捕獲異常,finally都會被執行。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容