異常是爲了反饋和處理/解決問題設計的一套機制。異常的頂級父類是Throwable,它有兩個子類:Error、Exception。下面分別詳細介紹兩者。java
一、Exception的定義:表示在合理的應用程序中出現的能夠處理的問題。ide
二、異常的分類:優化
三、異常的處理方式:this
四、自定義異常:若是在實際開發過程當中,遇到了問題可是在java中沒有對應的異常,那麼就須要本身定義一個異常。spa
若是定義的是一個編譯時異常,寫一個類繼承Exception。設計
若是須要定義一個運行時異常,須要繼承RuntimeException。日誌
示例以下:code
public class ExceptionDemo2 {public static String readTxtFile(String path) throws PathNotExistException, FileFormatException { // 路徑問題 if (!new File(path).exists()) // 須要將拋出的問題以對象的形式來進行封裝 // 若是跑出了異常對象,那麼該方法的後續代碼再也不執行 throw new PathNotExistException("親,這個路徑不存在哦~~~"); // 文件格式不正確 if (!path.endsWith(".txt")) { // xxxx.xxx.xxx int index = path.lastIndexOf('.'); String suffix = path.substring(index + 1); throw new FileFormatException("須要一個txt文件,可是傳入一個" + suffix + "文件"); } // 正常讀取 return "讀取成功~~~"; } } @SuppressWarnings("serial") class PathNotExistException extends Exception { // private String message; public PathNotExistException(String msg) { // this.message = msg; super(msg); } // public String getMessage() { // return message; // } } @SuppressWarnings("serial") class FileFormatException extends Exception { public FileFormatException(String msg) { super(msg); } }
五、異常的捕獲方式orm
public static void main(String[] args) /* throws FileFormatException */ { //1.分別處理異常 // try { // String msg = readTxtFile("D:\\a.bmp"); // System.out.println(msg); // } catch (PathNotExistException e) { // // 處理問題 // // System.out.println("捕獲到了一個問題:路徑不存在~~~"); // System.out.println(e.getMessage()); // } catch (FileFormatException e) { // // System.out.println("文件格式不正確~~~"); // System.out.println(e.getMessage()); // } //2. 統一處理 // try { // String msg = readTxtFile("D:\\a.bmp"); // System.out.println(msg); // } catch (Exception e) { // System.out.println(e.getMessage()); // } //3.分組處理 try { String msg = readTxtFile("D:\\a.bmp"); System.out.println(msg); } catch (PathNotExistException | FileFormatException e) { // 表示捕獲PathNotExistException或者是FileFormatException System.out.println(e.getMessage()); } }
六、異常對方法的重載沒有影響。對象
// 異常對方法的重載的有影響嗎? class A { public void m() throws IOException { System.out.println("A m()"); } public void m(int i) throws ParseException { System.out.println("A m(int)"); } } class B extends A { public void m() throws EOFException, FileNotFoundException, NullPointerException { System.out.println("B m()"); } }
七、異常對方法重寫的影響:在方法重寫的時候,子類中重寫的方法拋出的編譯時異常不能超過父類方法拋出的編譯時異常的範圍。即:子類不能拋出比父類更高級的異常。
八、finally:不管前邊的代碼執行成功與否,finally中的代碼都會執行一次。內存中的棧能夠分爲計算區和結果區;當try檢測到finally時,程序仍是會順序執行。只不過會返回結果會延遲,此時,當執行到try中的return語句時,會先將結果存儲到結果區,等到finally程序執行完畢後,再將結果返回。若是try 和 finally都有return語句,這以finally返回語句爲準。例如以下實例返回結果爲5。
public static void main(String[] args) { System.out.println(m()); } private static int m() { int i = 5; try { // 代碼依然是從上到下順次執行的 // 在執行try以前會先檢測是否有finally // 若是有finally,那麼會將try中的返回過程推後 // 棧內存的結構:計算區域,結果區域 -> 棧幀 // 實際執行過程:try->finally->方法返回實際結果 // 先執行try中的代碼 // 執行return語句,只是將結果放入結果區域 // i在計算區域繼續自增爲6 return i++; } finally { // 繼續執行finally // i在計算區域繼續自增爲7 // 執行完成finally,方法會將結果區域的值進行返回 i++; System.out.println("finally:" + i); } }
當返回的是一個引用類型時,因爲finally中值的改變是改變的結果區的數據,所以,此時會影響到返回結果。例如:
public class ExceptionDemo8 { public static void main(String[] args) { System.out.println(m()); } private static Student m() { Student s = new Student(); try { s.setName("翠花"); s.setAge(18); // 由於結果區域存儲的是s的地址 return s; } finally { s = new Student(); s.setName("周星星"); s.setAge(80); } } } class Student { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } }
此時,返回的結果是:周星星,80
九、若是方法拋出的是父類異常,那麼使用的時候也必須捕獲一個父類異常;再捕獲異常的時候,必須先捕獲子類異常後捕獲父類異常。緣由:若是先捕獲父類異常,父類異常中已經包含子類異常,就會報錯了。
十、當項目處在開發期間是,若是項目中出現了異常,打印這個異常的棧軌跡,而後根據這個軌跡進行調錯;若是項目已經上線,出現了異常,記錄錯誤日誌。
一、表示嚴重的錯誤。
二、出現以後不能處理。
三、出現以後只能儘可能優化代碼,減小錯誤出現的概率。