java異常拾遺

來源:互聯網
上載者:User

標籤:java異常   exception   throwable   

概述

當方法內部發生一項錯誤時,該方法會建立一個對象傳遞給運行時系統(runtime system),這個對象被稱為異常對象,包含錯誤的類型、發生位置,程式狀態等一系列資訊。

當一個方法拋出異常時,運行時系統會沿著調用棧(call stack)尋找該異常的處理方式 。

中,調用棧下面的方法調用了上面的方法,層層嵌套,一共四層:


調用第三個方法時拋出了一個異常,運行時系統就會沿著調用棧反向尋找該異常的處理常式,當該異常類型與某個例外處理常式聲明的異常類型一致時,系統就將該異常交給它處理。


如果系統沒能找到合適的例外處理常式,系統將會終止。

 

異常類型

java提供了兩種處理異常的方式:

(1)   使用try語句捕獲異常並處理;

(2)   使用throws關鍵字列出要拋出的異常類型,代表在本方法內不做處理,但是調用該方法的方法必須處理該異常或者繼續拋出。

 

並不是所有異常都需要顯式處理(這裡的處理代表在程式內部捕獲或者拋出),比如IOException、SQLException等是必須要處理的,而NullPointerException、ArithmeticException、IndexOutOfBoundsException等可以不作處理。

理解這一點,就要弄清異常的基本分類。


Checked Exception

這類異常是應用程式可以預見並能夠恢複的錯誤,比如,應用程式需要使用者輸入一個檔案名稱,然後程式將對這個檔案進行讀寫操作。假如使用者輸入的檔案名稱不存在,拋出java.io.FileNotFoundException,應用程式應該捕獲這個異常並提醒使用者。類似這種異常就屬於checked exception。

除了Error、RuntimeException以及兩者的子類,所有異常都屬於checked exception


Error

Error一般來說是應用程式外部引起的異常,應用程式通常不能預見並恢複。比如,程式順利開啟了一個檔案,但是由於硬體或者作業系統故障,不能夠讀取檔案中的內容,程式就會拋出java.io.IOError。


Runtime Exception

runtimeexception一般來說是程式內部引起的異常,應用程式通常能夠預見並恢複。這類異常的出現一般暗示程式存在bug。比如,還是檔案操作的例子,由於邏輯錯誤,傳入的檔案名稱為空白值,程式就會拋出一個NullPointerException。

雖然可以讓程式捕獲runtimeexception,但更合適的做法是剔除引起這類異常的bug。

 

java的異常類層次圖如下:



異常的捕獲

checked exception必須捕獲,而unchecked exception的捕獲不是必須的。例如:

import java.io.*;import java.util.List;import java.util.ArrayList; public class ListOfNumbers {     private List<Integer> list;    private static final int SIZE = 10;     public ListOfNumbers () {        list = new ArrayList<Integer>(SIZE);        for (int i = 0; i < SIZE; i++) {            list.add(new Integer(i));        }    }     public void writeList() {         try{         // FileWriter的構造方法 throws IOException, checked exception類型,必須捕獲        PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));         for (int i = 0; i < SIZE; i++) {            // get(int)方法throws IndexOutOfBoundsException,RuntimeException的子類,unchecked exception類型,不是必須要捕獲的            out.println("Value at: "+ i + " = " + list.get(i));        }        out.close();         }catch(IOException e){  //捕獲IOException                ...         }    }}

unchecked exception在一些特殊的情況下也可以選擇捕獲它,比如上面的程式,現在既要捕獲IOException,也要捕獲IndexOutOfBoundsException,改寫如下:

public void writeList() {         try{         // FileWriter的構造方法 throws IOException, checked exception類型,必須捕獲        PrintWriter out = new PrintWriter(new FileWriter("OutFile.txt"));         for (int i = 0; i < SIZE; i++) {            // get(int)方法throws IndexOutOfBoundsException,RuntimeException的子類,unchecked exception類型,不是必須要捕獲的            out.println("Value at: "+ i + " = " + list.get(i));        }        out.close();         }catch(IndexOutOfBoundsException e){  //捕獲IndexOutOfBoundsException                ...         }catch(IOException e){  //捕獲IOException                ...         }
 

從Java SE 7以後,一個catch塊可以捕獲多個異常,上面的捕獲語句可簡寫為:

catch (IndexOutOfBoundsException | IOException ex) {    ...}
需要注意的是,這種情況下,catch的參數(上例中的“ex”)預設是final的,不能夠在catch塊中對它再次賦值。

 

無論異常是否發生,try代碼塊退出後,finally代碼塊都會執行,常常用於釋放資源。例如:

  

public void writeList() {       PrintWriter out = null;    try{      out = new PrintWriter(new FileWriter("OutFile.txt"));       for (int i = 0; i < SIZE; i++) {          out.println("Value at: " +i + " = " + list.get(i));      }         }catch(IOException e){            ...    }finally{  //釋放資源             if(out!=null){                    out.close();             }    }  }

上例中,有三種情況可導致try代碼塊退出:

(1)newFileWriter("OutFile.txt")拋出IOException

(2)list.get(i)拋出IndexOutOfBoundsException

(3)無異常拋出,代碼執行完畢

無論發生了上面的那種情況,運行時系統都會保證finally代碼塊中的程式執行。

需要注意的是,如果在執行try-catch代碼塊的時候JVM退出了,或者執行try-catch代碼塊的線程被中斷或者殺死,finally代碼塊有可能不被執行

try-with-resources語句

在try中聲明的一個或多個資源,在程式結束後應該關閉,通常我們是在finally代碼塊中完成這項工作。 

從java 7開始,提供了一種更為簡潔有效寫法: try-with-resources語句。

使用形式如下:

static String readFirstLineFromFile(String path) throws IOException {    try (BufferedReader br =                   new BufferedReader(new FileReader(path))) {        return br.readLine();    }}
try-with-resources確保{}內的程式執行完畢後自動關閉資源,所有實現了java.lang. AutoCloseable介面(java 7新增的介面,java.lang.Closeable的父介面,)的對象都可以當作資源。


throw與throws

捕獲異常的前提是有方法拋出了異常。

throw關鍵字用於在方法體內部,發生錯誤的地方拋出異常。如:

public Object pop() {    Object obj;     if (size == 0) {  //棧為空白,拋出異常        throw new EmptyStackException();    }     obj = objectAt(size - 1);    setObjectAt(size - 1, null);    size--;    return obj;}
該方法用於從棧中彈出棧頂元素,但是,如果棧為空白就不能進行這項操作,所以就會拋出EmptyStackException異常。

 

當其他方法調用pop()方法時,就應該考慮到pop()可能會拋出的異常,如果如果pop()拋出的UncheckedException,可以不做額外的處理;如果pop()拋出的是checked Exception則必須進行處理,可以用try-catch捕獲,也可以選擇在本方法內不做捕獲,繼續用throws關鍵字拋出,如:

public void callPop() throws EmptyStackException {      ...      pop(); //該方法可能會拋出EmptyStackException      ...}
 

實際上,一個異常很多時候是由於另一個cause異常引起的,因為cause 自身也會有 cause,依此類推,就形成了鏈式異常(Chained Exceptions)。例如:

try {

 

} catch(IOException e) {  //捕獲到IOException時,拋出另一個異常

   throw new SampleException("Other IOException", e);

}

Throwable有一種造函數可以接受Throwable類型的參數作為引起該異常的cause,Throwable類的initCause(Throwable)、getCause()可以設定cause資訊、擷取cause資訊。


著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

java異常拾遺

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.