菜鳥學JAVA之——異常

異常

異常分爲錯誤(Error)與異常(Exception)

一、異常體系結構

java.lang.Throwable

  • java.lang.Error:一般不編寫針對性的代碼進行處理
  • java.lang.Exception:可以進行異常的處理
    • 編譯時異常(checked)(也稱“受檢異常”)
      • IOException
      • ClassNotFoundException
    • 運行時異常(unchecked)(也稱“非受檢異常”)
      • NullPointerException
      • ArrayIndexOutOfBoundsException
      • ClassCastException
      • NumberFormatException
      • InputMismatchException
      • ArithmeticException

二、Java異常處理的方式

  • 方式一:try-catch-finally

    舉個例子:小孩在放羊,這時狼來了,小孩發現這個狼只是個狼崽子,他自己就有能力解決。羊就該喫草還喫草,相當於代碼正常執行

  • 方式二:throws + 異常類型

    這個就相當於來了一隻老狼,小孩處理不了了,需要在山下喊人,讓成人來解決,大人如果不能解決就會找警察。這種處理方式就相當於方式二

三、異常的處理:抓拋模型

  • 過程一:“拋”:程序在正常執行的過程中,一旦出現了異常,就會在異常代碼處生成一個對應異常類的對象。並將此對象拋出。一旦拋出對象後,其後的代碼就不再執行。

    關於異常對象的產生:① 系統自動生成的異常對象(在產生異常的代碼出生成一個異常對象)

    ​ ② 手動的生成一個異常對象,並拋出(throw)

        • public class StudentTest {
              public static void main(String[] args) {
                  Student s = new Student();
                  s.regist(-1001);
              }
          }
          
          class Student {
              private int id;
              
              public void regist(int id) {
                  if(id > 0) {
                      this.id = id;
                  } else {
                      //System.out.println("您輸入的數據非法!");//這裏如果輸入的數據非法,他還會返回一個id的默認值,還是會出來一個結果。按理說輸入非法應該報錯
                      //手動拋出一個異常對象,一般這個對象都是運行時異常,或編譯時異常。如果是編譯時異常就需要捕獲處理
                      //手動拋出運行時異常,編譯可以通過,可以不用處理
                      //throw new RunTimeException("您輸入的數據非法!");
                      
                      //手動拋出編譯時異常,編譯都不會通過,這時就需要處理了
                      try {
                      	throw new Exception("您輸入的數據非法!");//手動拋出異常
                      } catch(Exception e) {
                          System.out.println(e.getMessage());
                      }
                      
                  }
              }
              @Override
              public String toString() {
                  return "Student " + "[id = " + id + "]";
              }
          }
          
          
          
  • 過程二:“抓”:可以理解爲異常的處理方式:① try-catch-finally ② throws

四、異常處理方式一:try-catch-finally 的使用

try {
    //可能出現異常的代碼
}catch(異常類型1 變量名1){
    //處理異常的方式1
}catch(異常類型2 變量名2){
    //處理異常的方式2
}catch(異常類型3 變量名3){
    //處理異常的方式3
}
...
finally{
    //一定會執行的代碼
}

說明:

  • finally是可選的。

  • 使用try將可能出現異常代碼包裝起來,在執行過程中,一旦出現異常,就會生成一個對應異常類的對象,根據此對象的類型,去catch中進行匹配

  • 一旦try中的異常對象匹配到某個catch時,就進入catch中進行異常的處理。一旦處理完成,就跳出當前的try-catch結構(在沒有寫finally的情況)。繼續執行其後的代碼。

  • catch中的異常類型如果沒有子父類關係,則誰聲明在上,誰聲明在下無所謂。

    catch中的異常類型如果滿足子父類關係,則要求子類一定聲明在父類的上面。否則,報錯

  • 常用的異常對象的處理的方式:① getMessage()(返回值類型是String) ② printStackTrace()(void,無返回值,其拋出的異常信息包含getMessage()拋出的,所以比較常用)

  • 在try結構中聲明的變量,在出了try結構以後,就不能再被調用

  • try-catch-finally結構可以嵌套。

體會1:使用try-catch-finally處理編譯時異常,使得程序在編譯時就不再報錯,但是運行時仍可能報錯。相當於我們使用try-catch-finally將一個編譯時可能出現的異常,延遲到運行時出現。

體會2:開發中,由於運行時異常比較常見,所以我們通常就不針對運行時異常編寫try-catch-finally了。

​ 針對編譯時異常,我們說一定要考慮異常的處理。

五、finally

  • finally中聲明的是一定會被執行的代碼。即使catch中 出現異常了,try中有return語句,catch中有return語句等情況。

    public void testMethod() {
        int num = method();
        System.out.println(num);
    }
    
    public int method() {
        try{
            int[] arr = new int[10];
            System.out.println(arr[10]);//①
            return 1;
        }catch(ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            return 2;
        } finally {
            System.out.println("我一定會被執行!");
            //return 3;
        }
    }
    

    如果不註釋①號代碼,則輸出語句爲:我一定被執行!/n 2

    如果註釋掉:輸出:我一定被執行!/n 1

    如果給finally裏面加一個語句return 3; 則不管有沒有異常都輸出:輸出:我一定被執行!/n 3

    來個情景對話方便理解:如果程序存在異常,那麼程序執行到catch代碼塊中。先執行e.printStackTrace();然後準備返回2,finally說等等,我還沒執行,我先執行。catch的return說,好,那你先執行,執行完了給我說一聲。然後finally就先執行第一句代碼,然後直接返回3,並沒有catch中return返回的機會。

    不管是遇到了一個return還是製造的異常,都先執行finally的語句

  • 像數據庫鏈接、輸入輸出流、網絡編程Socket等資源,JVM是不能自動的回收的,我們需要手動的進行資源的釋放。此時的資源釋放,就需要聲明在finally中。

六、異常處理方式二:throws + 異常類型

  • "throws + 異常類型"寫在方法的聲明處。指明此方法執行時,可能會拋出的異常類型。

    一旦當方法體執行時,出現異常,仍會在異常代碼處生成一個異常類的對象,此對象滿足throws後的異常類型時,就會被拋出。異常代碼後續的代碼,就不再執行!

  • 體會:try-catch-finally:真正的將異常處理掉了

    throws的方式只是將異常拋給了方法的調用者。並沒有真正將異常處理掉。(最多拋到main方法裏,你就需要用try-catch-finally將他處理了)

    歸根結底,最後都是需要用try-catch(-finally)來解決

  • 在開發過程中如何選擇使用try-catch-finally還是throws?

    • 如果父類中被重寫的方法沒有throws方式處理異常,則子類重寫的方法也不能使用throws,意味着如果子類重寫的方法中有異常,必須使用try-catch-finally方式處理。
    • 執行的方法a中,先後又調用了另外的幾個方法,這幾個方法時遞進關係執行的(比如:方法三要用到方法二得到的結果,方法二又需要方法一得到的結果)。我們建議這幾個方法使用throws的方式進行處理。而執行的方法a可以考慮使用try-catch-finally方法進行處理。

七、如何自定義異常類?

  • 繼承於先有的異常結構:RunTimeException、Excetion

  • 提供全局常量:serialVersionUID

  • 提供重載的構造器

    public class MyException extends RunTimeException {
        static final long serialVersionUID = -4321532432453543543L;
        
        public MyException() {
            
        }
        
        public MyException(String msg) {
            super(msg);
        }
    }
    

八、throw和throws的區別:

throw表示拋出一個異常類的對象,生成異常對象的過程。聲明在方法體內

throws屬於異常處理的一種方式,聲明在方法的聲明處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章