Java基礎-異常篇

1-認識異常

1.1-什麼是異常?

​ 異常,在Java程序中指的是:因程序問題而中斷程序執行的現象。java

1.2-異常分類

 
異常體系

​ 在Java中,爲了維護程序正常執行,Java提供了處理異常的異常機制(異常類)。數據庫

​ 在Java提供的異常機制中,其中java.lang.Throwable是根類,而根類的派生類有java.lang.Error和java.lang.Excepiton兩個子類。編程

​ Error,錯誤(絕症),該類型異常在程序中沒法處理,只能儘可能避免。數組

​ Excepiton,編譯期異常(寫源代碼時)(小毛病,好比:相似感冒),該類型異常在程序中是可處理的。Excepiton類型還有一個子類RunTimeException,表示運行期異常(程序運行的過程當中),該類型異常在程序中也是可處理的。網絡

​ 爲了更好的區分以上描述的異常分類,咱們看如下程序。ui

// 【Error異常】 // Exception in thread "main" java.lang.OutOfMemoryError: Java heap space // 內存溢出。超出了分配給JVM內存大小。 // 該程序只能修改源代碼解決問題。 int[]nums = new int[1024*1024*1024]; // 【Exception異常】 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // Unhandled exception: java.text.ParseException // 此處在編寫源代碼時就發生異常,該異常後續能夠經過相關的處理機制處理和避免 Date date = format.parse("2083-10-10"); // 【RunTimeException異常】 int[] nums = {1,2,3}; // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException // 在程序運行時出現的異常,數組下標超出。該異常能夠經過相關異常機制處理 System.out.println(nums[4]);

1.3-異常產生的過程

在編程中,爲了更好的處理異常,咱們首先要了解異常產生的過程。下面經過一段異常代碼來分析。spa

  • 代碼:調試

    // 需求:定義一個方法,用來獲取指定數組的指定位置的元素 public static void main(String[] args) { int[]nums = {1,2,3}; System.out.println(getElement(nums,4)); } public static int getElement(int[]arr,int index){ return arr[index]; }
  • 分析:日誌

    1. 在執行getElement方法的過程當中,JVM檢測出數組索引越界異常,此時JVM會作兩件事:
      • 建立一個ArrayIndexOutOfBoundsException異常對象,該對象中包含了異常的信息(內容、緣由、位置)
      • 由於getElment方法中沒有異常處理,JVM會把異常對象拋給getElment方法的調用處-main方法。
    2. main方法接收到了ArrayIndexOutOfBoundsException異常對象,也沒有處理異常,則會把異常對象拋給JVM
    3. JVM接收到了main方法後,會作兩件事:
      • 在控制檯打印異常信息(內容、緣由、位置)
      • 終止程序的執行。
  • 圖解:code

     
    異常產生的流程

     

2-處理異常

2.1 關鍵字

異常相關的關鍵字有:

  • try
  • catch
  • finally
  • throw
  • throws

2.2 拋出異常-throw

  • 做用:在指定的方法內部拋出異常。

  • 格式:throw new xxxException(參數)

    • 參數是字符串格式,用來描述異常。
  • 注意事項:

    1. throw關鍵字必須寫在方法內部。
    2. throw關鍵字後建立的對象必須是Exception或Exception的子類對象。
    3. throw關鍵字拋出的異常對象,咱們必須處理異常對象。
      • throw關鍵字拋出的時RunTimeException或RunTimeException子類異常對象時,咱們能夠不處理,由於JVM會默認處理(打印異常信息、中斷程序)。
      • throw關鍵字拋出的時編譯期異常時(編寫源代碼時),咱們必須處理(能夠經過throws或try-catch的方式處理)
  • 代碼:

    public static void main(String[] args) { int[]nums = {1,2,3}; // getElement(nums,4); // 異常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4 int[]nums2=null; getElement(nums2,0); // 異常java.lang.NullPointerException: 傳入的數組對象爲null } public static int getElement(int[]arr,int index){ if(arr==null){ throw new NullPointerException("傳入的數組對象爲null"); } if(index<0||index>=arr.length){ throw new ArrayIndexOutOfBoundsException("索引越界:" + index); } return arr[index]; }

2.3 Objects非空判斷

​ Objects中提供了一個方法,能夠檢測一個對象爲null並拋出異常,咱們來應用一下,並查看其源代碼更好的理解throw關鍵字的應用。

  • 方法名稱:public static <T> T requireNonNull(T obj):查看指定引用對象不是null。

  • 源代碼:

    public static <T> T requireNonNull(T obj) { if (obj == null) throw new NullPointerException(); return obj; }
  • 應用:

    public static void main(String[] args) { int[]nums = {1,2,3}; // getElement(nums,4); // 異常:java.lang.ArrayIndexOutOfBoundsException: 索引越界:4 int[]nums2=null; getElement(nums2,0); // 異常java.lang.NullPointerException } public static int getElement(int[]arr,int index){ Objects.requireNonNull(arr); // 應用 if(index<0||index>=arr.length){ throw new ArrayIndexOutOfBoundsException("索引越界:" + index); } return arr[index]; }

2.4 聲明異常-throws

當程序拋出一個異常對象給調用者時,調用者必需要處理異常,此時能夠選擇throws關鍵字來處理。

throws關鍵字的做用就是把異常對象繼續拋給其餘調用者,若其餘調用者沒有處理異常,則最終會拋給JVM來處理。

  • 格式:

    /* 修飾符 返回值類型 方法名() throws XXX1Exception,XXX2Exception... { throw new XXX1Exception("產生的緣由"); throw new XXX2Exception("產生的緣由"); } */
  • 注意事項:

    1. throws關鍵字必須寫在方法聲明出。
    2. throws關鍵字後聲明的異常必須是Exception或Exception子類異常。
    3. 方法內部拋出多個異常時,那麼throws關鍵字後必須聲明多個異常。
      • 若是拋出的多個異常之間存在繼承關係,那麼直接拋出父類便可。
    4. 調用了一個聲明異常的方法,調用者必須處理該異常,處理方式有:
      • 調用者繼續聲明throws拋給其餘調用者。最終拋給JVM。
      • 在調用者內部經過try-catch處理異常。
  • 代碼

    // 需求:定義一個讀取文件的方法,檢測文件的路徑和後綴名 public static void main(String[] args) throws Exception { retFile("a.txt"); } // 讀取文件的方法 // private static void retFile(String path) throws FileNotFoundException,IOException { private static void retFile(String path) throws IOException { // 若是後綴名不是.txt則拋出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件後綴名不是.txt"); } if(path.contains("c:")) { throw new IOException("文件路徑錯誤"); } }

2.5 捕獲處理異常-(try-catch)

throws聲明異常的弊端是:異常後續代碼沒法執行(由於交給了JVM,JVM會終止程序)。

try-catch可讓調用者處理異常,並會繼續執行後續程序。

  • 格式

    try { // 可能會發生異常的程序 // 若發生異常,try會檢測到異常對象 }catch(異常類型 變量) { // catch會接收到異常對象,能夠在此代碼塊中進行處理 }catch(異常類型 變量) { // catch會接收到異常對象,能夠在此代碼塊中進行處理 }...
  • throwable中經常使用的異常方法

    • public String getMessage() :獲取異常的描述信息,緣由(提示給用戶的時候,就提示錯誤緣由。
    • public String toString() :獲取異常的類型和異常描述信息(不用)。
    • public void printStackTrace() :打印異常的跟蹤棧信息並輸出到控制檯。
      • 包含了異常的類型,異常的緣由,還包括異常出現的位置,在開發和調試階段,都得使用printStackTrace。
  • 代碼

    // 需求:定義一個讀取文件的方法,檢測文件的路徑和後綴名 public static void main(String[] args) { try{ retFile("d.txt"); }catch (Exception e) { e.printStackTrace(); } System.out.println("後續代碼"); /* 執行結果: java.io.IOException: 文件路徑錯誤 at it.leilei.cn.demo01.Main01.retFile(Main01.java:27) at it.leilei.cn.demo01.Main01.main(Main01.java:12) 後續代碼 */ } // 讀取文件的方法 private static void retFile(String path) throws IOException { // 若是後綴名不是.txt則拋出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件後綴名不是.txt"); } if(!path.contains("c:")) { throw new IOException("文件路徑錯誤"); } }

2.6 finally代碼塊

  • finally關鍵字的做用:有一些特定的代碼不管異常是否發生,都須要執行。另外,由於異常會引起程序跳轉,致使有些語句執行 不到。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是必定會被執行的。

  • finally使用格式:try...catch...finally自身須要處理異常,最終還得關閉資源。

  • finally關鍵字的應用場景:當咱們在try語句塊中打開了一些物理資源(磁盤文件/網絡鏈接/數據庫鏈接等),咱們都得在使用完以後,最終關閉打開的資源。

  • 代碼:

    // 需求:定義一個讀取文件的方法,檢測文件的路徑和後綴名 public static void main(String[] args) { try{ retFile("d.txt"); }catch (Exception e) { e.printStackTrace(); }finally { System.out.println("釋放資源"); } System.out.println("後續代碼"); } // 讀取文件的方法 private static void retFile(String path) throws IOException { // 若是後綴名不是.txt則拋出 if(!path.contains(".txt")){ throw new FileNotFoundException("文件後綴名不是.txt"); } if(!path.contains("c:")) { throw new IOException("文件路徑錯誤"); } }

2.7 異常處理注意事項

  • 多個異常使用捕獲又該如何處理呢?

    1. 多個異常分別處理。
    2. 多個異常一次捕獲,屢次處理。
    3. 多個異常一次捕獲一次處理
  • 通常咱們是使用一次捕獲屢次處理方式,格式以下:

    • 格式:

      try{ 編寫可能會出現異常的代碼 }catch(異常類型A e){ 當try中出現A類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日誌/打印異常信息/繼續拋出異常 }catch(異常類型B e){ 當try中出現B類型異常,就用該catch來捕獲. 處理異常的代碼 //記錄日誌/打印異常信息/繼續拋出異常 }
    • 注意:這種異常處理方式,要求多個catch中的異常不能相同,而且若catch中的多個異常之間有子父類異

      常的關係,那麼子類異常要求在上面的catch處理,父類異常在下面的catch處理。

  • 運行時異常被拋出能夠不處理。即不捕獲也不聲明拋出(JVM默認會進行處理)。

  • 若是finally有return語句,永遠返回finally中的結果,避免該狀況.

    public static void main(String[] args) { int num = getNum(); System.out.println(num); // 100 } // 讀取文件的方法 public static int getNum() { int a = 10; try { return a; }catch (Exception e){} finally { a = 100; return a; } }
  • 若是父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異 常。

    class Fu{ // 若是父類拋出了多個異常,子類重寫父類方法時,拋出和父類相同的異常或者是父類異常的子類或者不拋出異 常。 public void show1() throws IndexOutOfBoundsException{}; } class Zi extends Fu{ // 子類重寫父類方法時,拋出和父類相同的異常 // public void show1() throws IndexOutOfBoundsException{}; // 或者是父類異常的子類ArrayIndexOutOfBoundsException 繼承 IndexOutOfBoundsException // public void show1() throws ArrayIndexOutOfBoundsException{}; // 不拋出異常 public void show1() {}; }

3-自定義異常類

3.1 爲何要自定義異常類?

​ 咱們說了Java中不一樣的異常類,分別表示着某一種具體的異常狀況,那麼在開發中老是有些異常狀況是SUN沒有定義好的,此時咱們根據本身業務的異常狀況來定義異常類。例如年齡負數問題,考試成績負數問題等等。

3.2 什麼是自定義異常類?

​ 在開發中根據本身業務的異常狀況來定義異常類.

​ 自定義一個業務邏輯異常: RegisterException。一個註冊異常類。

3.3 如何定義異常類

  1. 自定義一個編譯期異常: 自定義類 並繼承於 java.lang.Exception 。
  2. 自定義一個運行時期的異常類:自定義類 並繼承於 java.lang.RuntimeException 。

3.4 代碼

要求:咱們模擬註冊操做,若是用戶名已存在,則拋出異常並提示:親,該用戶名已經被註冊。

public static void main(String[] args) { // 接收用戶註冊的用戶名 String name = new Scanner(System.in).next(); try{ check(name); }catch (RegisterException e){ e.printStackTrace(); return; } System.out.println("註冊成功"); } public static void check(String n) throws RegisterException{ String[]users={"張三","李四","王五"}; for (int i = 0; i < users.length; i++) { if (n.equals( users[i])) { throw new RegisterException("親,該用戶名已經註冊"); } } }
public class RegisterException extends Exception{ public RegisterException(){ super(); } public RegisterException(String message){ super(message); } }
相關文章
相關標籤/搜索