軟件程序在運行過程當中,很是可能遇到問題,咱們稱之爲異常,英文是:Exception,意思是例外。遇到這些例外狀況,或者叫異常,咱們怎麼讓寫的程序作出合理的處理,安全的退出,而不至於程序崩潰呢?java
在 Java 中一個異常的產生,主要有以下三種緣由:數據庫
Java 經過面向對象的方法來處理異常。在一個方法的運行過程當中,若是發生了異常,則這個方法會產生表明該異常的一個對象,並把它交給運行時的系統,運行時系統尋找相應的代碼來處理這一異常。數組
咱們把生成異常對象,並把它提交給運行時系統的過程稱爲拋出(throw)異常。運行時系統在方法的調用棧中查找,直到找到可以處理該類型異常的對象,這一個過程稱爲捕獲(catch)異常。安全
Java 異常強制用戶考慮程序的強健性和安全性。異常處理不該用來控制程序的正常流程,其主要做用是捕獲程序在運行時發生的異常並進行相應處理。編寫代碼處理某個方法可能出現的異常,可遵循以下三個原則:學習
在 Java 中全部異常類型都是內置類 java.lang.Throwable 類的子類,即 Throwable 位於異常類層次結構的頂層。Throwable 類下有兩個異常分支 Exception 和 Error,如圖所示。測試
Throwable 類是全部異常和錯誤的父類,下面有 Error 和 Exception 兩個子類分別表示錯誤和異常。其中異常類 Exception 又分爲運行時異常和非運行時異常,這兩種異常有很大的區別,也稱爲不檢查異常(Unchecked Exception)和檢查異常(Checked Exception)。this
運行時異常都是 RuntimeException 類及其子類異常,如 NullPointerException、IndexOutOfBoundsException 等,這些異常是不檢查異常,程序中能夠選擇捕獲處理,也能夠不處理。這些異常通常由程序邏輯錯誤引發,程序應該從邏輯角度儘量避免這類異常的發生。線程
非運行時異常是指 RuntimeException 之外的異常,類型上都屬於 Exception 類及其子類。從程序語法角度講是必須進行處理的異常,若是不處理,程序就不能編譯經過。如 IOException、ClassNotFoundException 等以及用戶自定義的 Exception 異常,通常狀況下不自定義檢查異常。下表中列出了一些常見的異常類型及它們的做用。指針
異常類型 | 說明 |
---|---|
Exception | 異常層次結構的根類 |
RuntimeException | 運行時異常,多數 java.lang 異常的根類 |
ArithmeticException | 算術譜誤異常,如以零作除數 |
ArraylndexOutOfBoundException | 數組大小小於或大於實際的數組大小 |
NullPointerException | 嘗試訪問 null 對象成員,空指針異常 |
ClassNotFoundException | 不能加載所需的類 |
NumberF ormatException | 數字轉化格式異常,好比字符串到 float 型數字的轉換無效 |
IOException | I/O 異常的根類 |
F ileN otF oundException | 找不到文件 |
EOFException | 文件結束 |
InterruptedException | 線程中斷 |
IllegalArgumentException | 方法接收到非法參數 |
ClassCastException | 類型轉換異常 |
SQLException | 操做數據庫異常 |
捕獲異常是經過3個關鍵詞來實現的:try-catch-finally。用try來執行一段程序,若是出現異常,系統拋出一個異常,能夠經過它的類型來捕捉(catch)並處理它,最後一步是經過finally語句爲異常處理提供一個統一的出口,finally所指定的代碼都要被執行(catch語句可有多條;finally語句最多隻能有一條,根據本身的須要無關緊要)。如圖所示。code
上面過程詳細解析:
1. try:
try語句指定了一段代碼,該段代碼就是異常捕獲並處理的範圍。在執行過程當中,當任意一條語句產生異常時,就會跳過該條語句中後面的代碼。代碼中可能會產生並拋出一種或幾種類型的異常對象,它後面的catch語句要分別對這些異常作相應的處理。
一個try語句必須帶有至少一個catch語句塊或一個finally語句塊 。
注意事項
當異常處理的代碼執行結束之後,不會回到try語句去執行還沒有執行的代碼。
2. catch:
n-每一個try語句塊能夠伴隨一個或多個catch語句,用於處理可能產生的不一樣類型的異常對象。
n-經常使用方法,這些方法均繼承自Throwable類 。
u-toString ()方法,顯示異常的類名和產生異常的緣由
u-getMessage()方法,只顯示產生異常的緣由,但不顯示類名。
u-printStackTrace()方法,用來跟蹤異常事件發生時堆棧的內容。
n-catch捕獲異常時的捕獲順序:
u-若是異常類之間有繼承關係,在順序安排上需注意。越是頂層的類,越放在下面,再否則就直接把多餘的catch省略掉。 也就是先捕獲子類異常再捕獲父類異常。
2. finally:
n-有些語句,不論是否發生了異常,都必需要執行,那麼就能夠把這樣的語句放到finally語句塊中。
n-一般在finally中關閉程序塊已打開的資源,好比:關閉文件流、釋放數據庫鏈接等。
try-catch-finally語句塊的執行過程:
try-catch-finally程序塊的執行流程以及執行結果比較複雜。
基本執行過程以下:
程序首先執行可能發生異常的try語句塊。若是try語句沒有出現異常則執行完後跳至finally語句塊執行;若是try語句出現異常,則中斷執行並根據發生的異常類型跳至相應的catch語句塊執行處理。catch語句塊能夠有多個,分別捕獲不一樣類型的異常。catch語句塊執行完後程序會繼續執行finally語句塊。finally語句是可選的,若是有的話,則不論是否發生異常,finally語句都會被執行。
注意事項
典型代碼
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class Test8 { public static void main(String[] args) { FileReader reader = null; try { reader = new FileReader("d:/a.txt"); char c = (char) reader.read(); char c2 = (char) reader.read(); System.out.println("" + c + c2); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { if (reader != null) { reader.close(); } } catch (Exception e) { e.printStackTrace(); } } } }
當CheckedException產生時,不必定馬上處理它,能夠再把異常throws出去。
在方法中使用try-catch-finally是由這個方法來處理異常。可是在一些狀況下,當前方法並不須要處理髮生的異常,而是向上傳遞給調用它的方法處理。
若是一個方法中可能產生某種異常,可是並不能肯定如何處理這種異常,則應根據異常規範在方法的首部聲明該方法可能拋出的異常。
若是一個方法拋出多個已檢查異常,就必須在方法的首部列出全部的異常,之間以逗號隔開。
注意事項
方法重寫中聲明異常原則:子類重寫父類方法時,若是父類方法有聲明異常,那麼子類聲明的異常範圍不能超過父類聲明的範圍。
典型代碼
import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class Test9 { public static void main(String[] args) { try { readFile("joke.txt"); } catch (FileNotFoundException e) { System.out.println("所需文件不存在!"); } catch (IOException e) { System.out.println("文件讀寫錯誤!"); } } public static void readFile(String fileName) throws FileNotFoundException, IOException { FileReader in = new FileReader(fileName); int tem = 0; try { tem = in.read(); while (tem != -1) { System.out.print((char) tem); tem = in.read(); } } finally { in.close(); } } }
在程序中,可能會遇到JDK提供的任何標準異常類都沒法充分描述清楚咱們想要表達的問題,這種狀況下能夠建立本身的異常類,即自定義異常類。
自定義異常類只需從Exception類或者它的子類派生一個子類便可。
自定義異常類若是繼承Exception類,則爲受檢查異常,必須對其進行處理;若是不想處理,可讓自定義異常類繼承運行時異常RuntimeException類。
習慣上,自定義異常類應該包含2個構造器:一個是默認的構造器,另外一個是帶有詳細信息的構造器。
示例:
自定義異常:
/**IllegalAgeException:非法年齡異常,繼承Exception類*/ class IllegalAgeException extends Exception { //默認構造器 public IllegalAgeException() { } //帶有詳細信息的構造器,信息存儲在message中 public IllegalAgeException(String message) { super(message); } }
自定義異常的使用:
class Person { private String name; private int age; public void setName(String name) { this.name = name; } public void setAge(int age) throws IllegalAgeException { if (age < 0) { throw new IllegalAgeException("人的年齡不該該爲負數"); } this.age = age; } public String toString() { return "name is " + name + " and age is " + age; } } public class TestMyException { public static void main(String[] args) { Person p = new Person(); try { p.setName("Lincoln"); p.setAge(-1); } catch (IllegalAgeException e) { e.printStackTrace(); System.exit(-1); } System.out.println(p); } }
執行結果:
1.要避免使用異常處理代替錯誤處理,這樣會下降程序的清晰性,而且效率低下。
2.處理異常不能夠代替簡單測試---只在異常狀況下使用異常機制。
3.不要進行小粒度的異常處理---應該將整個任務包裝在一個try語句塊中。
4.異常每每在高層處理(先了解!後面作項目會說!) 。