黑馬程式員-Java異常詳解

來源:互聯網
上載者:User

標籤:程式員   異常   java   

——Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! ——-

異常的介紹Java中的異常就是那些會阻礙當前程式運行,使程式執行可能失敗的一些可能情況,如程式中出現除零錯誤,數組下標越界等。異常在Java中被封裝成了一個類,繼承自 Throwable,名為 Exception,它有很多子類,分別描述了系統中很多常見的異常情況,這些異常機制的出現使得編寫程式時對一些問題的處理變得尤為方便,下面是一些簡單的使用方式。異常捕獲的一般格式
/** * javac ExceptionDemo.javac * java ExceptionDemo * 輸出:String index out of range: 3 */class ExceptionDemo {    public static void main(String[] args) {        try {            // 可能產生異常的代碼放到try內            System.out.println("Hi".charAt(3));        } catch(Exception e) {            // 對異常的處理            System.out.println(e.getMessage());        }    }}
當將 catch中的 Exception換成 StringIndexOutOfBoundsException時,輸出結果同樣為 String index out of range: 3,如下:這裡 ExceptionStringIndexOutOfBoundsException的父類,子類的對象賦值給父類的類型,這在Java中稱作多態。
/** * 輸出:String index out of range: 3 */class ExceptionDemo {    public static void main(String[] args) {        try {            // 可能產生異常的代碼放到try內            System.out.println("Hi".charAt(3));        } catch(StringIndexOutOfBoundsException e) {            // 對異常的處理            System.out.println(e.getMessage());        }    }}
異常的繼承關係從 Exception的繼承關係圖可以清楚的知道 Exception的父類及其子類的關係,超類是 ThrowableErrorException的共同超類), Throwable的超類便是 Object(除本身外Java中所有類的直接或者間接超類)。以 Exception結尾的類都是繼承自 Exception

try內有多條語句時,可能會產生多種異常,下列代碼雖然加上了異常捕獲操作但是沒有還是產生了異常,程式崩潰。
/** * 輸出:H *       Exception in thread "main" java.lang.ArithmeticException: / by zero *       at ExceptionDemo3.main(ExceptionDemo3.java:10) */class ExceptionDemo3 {    public static void main(String[] args) {        try {            // 可能產生異常的代碼放到try內            System.out.println("Hi".charAt(0));            System.out.println(123 / 0);        } catch(StringIndexOutOfBoundsException e) {            // 對異常的處理            System.out.println(e.getMessage());        }    }}
原因是雖然有catch來捕獲異常,但是僅僅捕獲的是 StringIndexOutOfBoundsException異常,這條異常只有 System.out.println("Hi".charAt(0));才會產生。而 System.out.println(123 / 0);這條語句會產生另一種異常,叫做 ArithmeticException,即運算異常。而這條異常沒有相應的捕獲語句,所以虛擬機器採用預設處理方式,即讓程式崩潰。加上 ArithmeticException 異常捕獲後便可以正常處理異常,如下:
/** * 輸出:H *       異常:/ by zero */class ExceptionDemo3 {    public static void main(String[] args) {        try {            // 可能產生異常的代碼放到try內            System.out.println("Hi".charAt(0));            System.out.println(123 / 0);        } catch(StringIndexOutOfBoundsException e) {            // 對異常的處理            System.out.println(e.getMessage());        } catch(ArithmeticException e) {            System.out.println("異常:" + e.getMessage());        }    }}
難道try內有大量語句時,會產生很多異常的情況就要加很多個 catch?當然你可以像第一個樣本那樣使用 Exception來接收所有異常,但是這樣又會有問題,那就是所有異常都會統一處理,那麼就使用 Exception和其他異常混合使用的情況,這種情況的時候要注意一點, Exception一定要放在最後面一條 catch中,否則編譯會報錯。正確寫法如下:
/** * 輸出:H *       異常:/ by zero */class ExceptionDemo3 {    public static void main(String[] args) {        try {            // 可能產生異常的代碼放到try內            System.out.println("Hi".charAt(0));            System.out.println(123 / 0);        } catch(StringIndexOutOfBoundsException e) {            // 對異常的處理            System.out.println(e.getMessage());        } catch(ArithmeticException e) {            System.out.println("異常:" + e.getMessage());        } catch(Exception e) {            System.out.println(e.getMessage());        }     }}
finally關鍵字Java異常捕獲中的另一個關鍵字 finally,同 catch的用法類似,不過 finally後沒有類型, finally的功能是作為 try...catch...finally中必然執行的一段。也就是說 try內的代碼產生或者沒有產生異常,最終都會執行 finally內的代碼。這可以應用到一些網路操作中,如訪問資料庫時有開啟資料庫,當操作資料庫時出現了錯誤,那麼在 finally中寫上關閉資料庫的操作便起到了很好的作用。避免系統開啟很多資料庫連接而無法關閉且又無法操作,這樣會非常消耗系統資源。訪問網路時也是同樣的道理。一些 finally的示範如下:
/** * 輸出: * B * C       */class ExceptionDemo4 {    public static void main(String[] args) {        try {            int num = 4 / 0; // 製作異常            System.out.println("A");        } catch (Exception e) {            System.out.println("B");        } finally {            System.out.println("C");        }    }}/** * 輸出: * A * B * C       */class ExceptionDemo4 {    public static void main(String[] args) {        try {            System.out.println("A");            int num = 4 / 0; // 製作異常        } catch (Exception e) {            System.out.println("B");        } finally {            System.out.println("C");        }    }}/** * 輸出: * 4 * 4 * 0       */class ExceptionDemo4 {    public static void main(String[] args) {        int num = 4;        try {            System.out.println(num);            int n = 10 / 0;  // 製造異常            num += 2;   // 異常發生後會立即進入異常處理部分        } catch (Exception e) {            System.out.println(num);            num = 0;        } finally {            System.out.println(num);        }    }}
try內的代碼在執行時碰到了異常後便不再繼續執行,而是跳到對應的異常處理程式碼片段執行,然後再執行 finally段的代碼。在帶有傳回值的函數中時, finally的執行如下:
/** * 輸出: * try:4 * catch:4 * finally:5 * main:4      */class ExceptionDemo5 {    public static void main(String[] args) {        System.out.println("main:" + method());    }    public static int method() {        int num = 4;        try {            System.out.println("try:" + num);            int n = 10 / 0;  // 製造異常        } catch (Exception e) {            System.out.println("catch:" + num);            return num;        } finally {            num ++;            System.out.println("finally:" + num);        }        return 0;    }}
finally之前出現了 return語句時,傳回值的內容會被壓棧,所以在 finally中修改 num的值是不會影響最終在 main函數中接收到的傳回值的內容的,這也體現了 finally一定會執行的一點。但是當遇到下面這種情況就要另當別論了:
import java.io.File;import java.io.FileOutputStream;import java.io.IOException;/** * 檔案內容為:Hello * 若將System.exit(0);注釋掉,檔案內容為Hi */class ExceptionDemo5 {    public static void main(String[] args) {        try {            FileOutputStream fout = new FileOutputStream(new File("E:\\ex.txt"));            fout.write("Hello".getBytes());            fout.close();            System.exit(0); // 直接退出系統        } catch (IOException e) {        } finally {            try {                FileOutputStream fout = new FileOutputStream(new File("E:\\ex.txt"));                fout.write("Hi".getBytes());                fout.close();            } catch (IOException e) {            }        }    }}
所以 finally的內容必然執行也是要建立再程式還處於正在啟動並執行狀態,程式已退出虛擬機器當然無法再執行 finally的內容了。 try...finally組合

除了try...catch...finally還有一種try...finally組合方式,即去掉catch段。若程式碼片段拋出的是RuntimeException便將異常拋給上一層,若是非RuntimeException或其子類便會編譯錯誤。(ArithmeticException屬於RuntimeException

/** * 輸出: * method:finally * main:/ by zero */class ExceptionDemo6 {    public static void main(String[] args) {        try {            method();        } catch(Exception e) {            System.out.println("main:" + e.getMessage());        }    }    public static void method() {        try {            int num = 6 / 0;        } finally {            System.out.println("method:finally");        }    }}
異常的拋出 throws對於異常的處理可以使用 try...catch,可以使用 try...catch...finally,也可以使用 try..finally,當然還有其他方式,你可以使用 throws把異常拋給上一層,這裡的上一層指的是如 main函數調用 method方法,對於 method方法來說 main函數就是上一層。
/** * 輸出: * main:Hello */class ExceptionDemo7 {    public static void main(String[] args) {        try {            method();        } catch(ClassNotFoundException e) {            System.out.println("main:" + e.getMessage());        }    }    public static void method() throws ClassNotFoundException {        Class<?> c = Class.forName("Hello");    }}
多個異常的拋出時可以在 throws後面使用 ,隔開,而拋出一條異常是使用 throw來實現的,如下:
/** * 輸出: * main:-Message- */class ExceptionDemo7 {    public static void main(String[] args) {        try {            method();        } catch(ClassNotFoundException e) {            System.out.println("main:" + e.getMessage());        } catch(Exception e) {            System.out.println("main:" + e.getMessage());        }    }    public static void method() throws ClassNotFoundException, IllegalAccessException {        // Class<?> c = Class.forName("Hello");        throw(new IllegalAccessException("-Message-"));    }}
自訂異常自訂異常其實很簡單,只需要繼承 Exception即可,或者繼承 Exception的子類,如下:
/** * 輸出: * main:My Exception */class MyException extends Exception {    public MyException(String msg) {        super(msg);    }}class ExceptionDemo7 {    public static void main(String[] args) {        try {            method();        } catch(MyException e) {            System.out.println("main:" + e.getMessage());        }    }    public static void method() throws MyException {        throw(new MyException("My Exception"));    }}
RuntimeException簡介當拋出 RuntimeException或者 RuntimeException的子類時無需使用 throws在方法名後面標出,這一類異常可能無法通過捕獲處理很好地處理,如除零錯誤發生時即使捕獲到了異常,但是後面的運算結果是會受到影響的,一定會出現一個不正確的運算結果。如上面出現過的除零異常,無需在方法名後加異常類型說明:
/** * 輸出: * method:finally * main:/ by zero */class ExceptionDemo6 {    public static void main(String[] args) {        try {            method();        } catch(Exception e) {            System.out.println("main:" + e.getMessage());        }    }    public static void method() /*這裡不需要加 ArithmeticException*/{        try {            int num = 6 / 0;        } finally {            System.out.println("method:finally");        }    }}

黑馬程式員-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.