推薦學習:《》
Java中的異常(Exception)又稱為例外,是一個在程式執行期間發生的事件,它中斷正在執行程式的正常指令流。為了能夠及時有效地處理程式中的執行錯誤,必須使用異常類。
在Java中異常產生,主要是有三種原因:
(1)編寫程式程式碼中的錯誤產生的異常,比如陣列越界、空指標異常等,這種異常叫做未檢查的異常,一般需要在類中處理這些異常
(2)Java內部錯誤發生的異常,Java虛擬機器器產生異常
(3)通過throw(丟擲異常)語句手動生成的異常,這種異常叫做檢查的異常,一般是用來給方法呼叫者一些必要的資訊
(1)Throwable:是異常體系的頂層類,其派生出兩個重要的子類, Error 和 Exception
而 Error 和 Exception 兩子類分別表示錯誤和異常。
區別就是不檢查異常(Unchecked Exception)和檢查異常(Checked Exception)。
(2)Exception 類用於使用者程式可能出現的異常情況,它也是用來建立自定義異常型別類的類。
(3)Error 定義了在通常環境下不希望被程式捕獲的異常。Error 型別的異常用於 Java 執行時由系統顯示與執行時系統本身有關的錯誤。堆疊溢位是這種錯誤的一例。
異常可能在編譯時發生,也有可能在程式執行時發生,根據發生時機不同,可以分為:
執行時異常都是 RuntimeException 類及其子類異常,如 NullPointerException、IndexOutOfBoundsException 等,這些異常是不檢查異常,程式中可以選擇捕獲處理,也可以不處理。這些異常一般由程式邏輯錯誤引起,程式應該從邏輯角度儘可能避免這類異常的發生。
比如:
編譯時異常是指 RuntimeException 以外的異常,型別上都屬於 Exception 類及其子類。從程式語法角度講是必須進行處理的異常,如果不處理,程式就不能編譯通過。如 IOException、ClassNotFoundException 等以及使用者自定義的 Exception 異常,一般情況下不自定義檢查異常。
比如
class Person implements Cloneable{ @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class Test01 { public static void main(String[] args) { Person person =new Person(); Person person1 =(Person) person.clone(); } }
錯誤在程式碼中是客觀存在的. 所以要讓程式出現問題的時候快速通知程式猿.
通知有兩種方式:
(1)LBYL 在操作之前就做充分的檢查
private static int pide() { int a = 0, b = 0; Scanner scanner = new Scanner(System.in); a = scanner.nextInt(); b = scanner.nextInt(); if (b == 0) { System.out.println("除數為0"); return 0; } else { return a / b; } }
缺點:正常流程和錯誤處理流程程式碼混在一起, 程式碼整體條理不清晰。
(2)EAFP 先操作遇到問題再處理
private static int pide() { int a = 0, b = 0; try (Scanner scanner = new Scanner(System.in)) { a = scanner.nextInt(); b = scanner.nextInt(); return a / b; } catch (ArithmeticException exception) { System.out.println("除數為0"); return 0; } }
優點:正常流程和錯誤流程是分離開的, 程式設計師更關注正常流程,程式碼更清晰,容易理解程式碼
處理異常的核心思想就是EAFP
在編寫程式時,如果程式中出現錯誤,這就需要將錯誤的資訊通知給呼叫者
這裡就可以藉助關鍵字throw,丟擲一個指定的異常物件,將錯誤資訊告知給呼叫者。
比如寫一個執行時異常
public static void func2(int a) { if(a == 0) { //丟擲的是一個指定的異常,最多的使用方式是,丟擲一個自定義的異常 throw new RuntimeException("a==0"); } } public static void main(String[] args) { func2(0); }
注意:
(1)throw必須寫在方法體內部
(2)如果丟擲的是編譯時異常,使用者就必須要處理,否則無法通過編譯
(3)如果丟擲的執行時異常,則可以不用處理,直接交給JVM來處理
(4)一旦出現異常,後面的程式碼就不會執行
throws處在方法宣告時參數列之後,當方法中丟擲編譯時異常,使用者不想處理該異常,
此時就可以藉助throws將異常拋 給方法的呼叫者來處理。
格式:
修飾符 返回值型別 方法名(參數列) throws 異常型別 {
}
如果說方法內部丟擲了多個異常,throws之後就必須跟多個異常型別,用逗號進行分隔
public static void func2(int a) throws CloneNotSupportedException, FileNotFoundException { if(a == 0) { throw new CloneNotSupportedException("a==0"); } if(a == 1) { throw new FileNotFoundException(); } }
如果丟擲多個異常型別有父子關係,直接宣告父類別
public static void func2(int a) throws Exception { if(a == 0) { throw new CloneNotSupportedException("a==0"); } if(a == 1) { throw new FileNotFoundException(); } }
呼叫宣告丟擲異常的方法時,呼叫者必須對該異常進行處理,或者繼續使用throws丟擲
public static void main(String[] args) throws FileNotFoundException, CloneNotSupportedException { func2(0); }
當程式丟擲異常的時候,程式設計師通過try-each處理了異常
public static void main(String[] args) { try { int[] array = null; System.out.println(array.length); }catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); } System.out.println("其他程式!"); }
如果程式丟擲異常,不處理異常,那就會交給JVM處理,JVM處理就會把程式立即終止
並且,即使用了try-each 也必須捕獲一個對應的異常,如果不是對應異常,也會讓JVM進行處理
如果try丟擲多個異常,就必須用多個catch進行捕獲
這裡注意,用多個catch進行捕獲,不是同時進行捕獲的,因為不可能同時拋不同的異常
public static void main(String[] args) { try { int[] array = null; System.out.println(array.length); }catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); }catch (ArithmeticException e) { System.out.println("捕獲到了一個算術異常!"); } System.out.println("其它程式碼邏輯!"); }
也可以簡寫一下
public static void main(String[] args) { try { int[] array = null; System.out.println(array.length); }catch (NullPointerException | ArithmeticException e) { System.out.println("捕獲到了一個空指標或算術異常!"); } System.out.println("其它程式碼邏輯!"); }
如果異常之間具有父子關係,那就必須子類異常在前,父類別異常在後catch,不然會報錯
public static void main(String[] args) { try { int[] array = null; System.out.println(array.length); }catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); }catch (Exception) { System.out.println("捕獲到了一個算術異常!"); } System.out.println("其它程式碼邏輯!"); }
finally用來進行資源回收,不論程式正常執行還是退出,都需要回收資源
並且異常會引發程式的跳轉,可能會導致有些語句執行不到
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); try { int[] array = null; System.out.println(array.length); }catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); }catch (ArithmeticException e) { System.out.println("捕獲到了一個算術異常!"); }finally { scanner.close(); System.out.println("進行資源關閉!"); } System.out.println("其它程式碼邏輯!"); }
如果不為空,那麼finally還會被執行嗎
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); try { int[] array = {1,2,3}; System.out.println(array.length); }catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); }catch (ArithmeticException e) { System.out.println("捕獲到了一個算術異常!"); }finally { scanner.close(); System.out.println("進行資源關閉!"); } System.out.println("其它程式碼邏輯!"); }
所以,不管程式會不會丟擲異常,finally都會執行
如果將資源寫在try中會自動幫助,關掉資源的
public static void main(String[] args) { try (Scanner scanner = new Scanner(System.in)) { int[] array = {1, 2, 3}; System.out.println(array.length); } catch (NullPointerException e) { System.out.println("捕獲到了一個空指標異常!"); } catch (ArithmeticException e) { System.out.println("捕獲到了一個算術異常!"); } finally { System.out.println("進行資源關閉!"); } System.out.println("其它程式碼邏輯!"); }
下面看這一段程式碼
public static int func(int a) { try{ if(a == 0) { throw new ArithmeticException(); } return a; } catch (ArithmeticException e) { System.out.println("算術異常!"); } finally { return 20; } } public static void main(String[] args) { System.out.println(func(10)); }
可以發現即使有return,finally也會被執行
總結一下:
throw丟擲異常,throws宣告異常
finally語句一定會執行
雖然java中有很多異常類,但是在實際開發中所遇到的一些異常,不能完全表示,
所以這就需要我們自定義異常類
舉一個例子
先自定義一個執行時異常
//自定義了一個執行時異常 public class MyException extends RuntimeException{ public MyException() { } public MyException(String message) { super(message); } }
寫一個類來捕獲這個自定義異常
public class Test04 { public static void func(int a ) { throw new MyException("呵呵!"); } public static void main(String[] args) { try { func(20); }catch (MyException myException) { myException.printStackTrace(); }finally { System.out.println("sadasdasd"); } } }
下面寫一個使用者登入的自定義異常類
class UserNameException extends RuntimeException { public UserNameException() { } public UserNameException(String message) { super(message); } } class PasswordException extends RuntimeException { public PasswordException() { } public PasswordException(String message) { super(message); } }
public class LogIn { private static String uName = "admin"; private static String pword = "1111"; public static void loginInfo(String userName, String password) { if ( !uName.equals(userName)) { throw new UserNameException("使用者名稱錯誤!"); } if ( !pword.equals(password)) { throw new RuntimeException("密碼錯誤!"); } System.out.println("登入成功!"); } public static void main(String[] args) { try { loginInfo("admin","1111"); } catch (UserNameException e) { e.printStackTrace(); } catch (PasswordException e) { e.printStackTrace(); } } }
注意:
自定義異常預設會繼承 Exception 或者 RuntimeException
繼承於 Exception 的異常預設是受查異常
繼承於 RuntimeException 的異常預設是非受查異常
推薦學習:《》
以上就是一起分析Java中異常的產生原因及處理的詳細內容,更多請關注TW511.COM其它相關文章!