異常

一、異常的產生

先看下面的這個demo:

/*
 * 異常的產生
 */

public class ExceptionDemo {
    public static void main(String[] args) {
        System.out.println(0/0);
        System.out.println("hello world");
    }
}

此時程序就產生 的異常如下:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at exceptions.ExceptionDemo.main(ExceptionDemo.java:11)

分析:

  • JVM檢測到了問題(0是除數的問題),于是程序發生了異常
  • JVM就把這個異常進行了對象的封裝new ArithmeticException()
  • 異常對象被拋給調用者main中,main方法接收到這個異常后,由于程序中沒有對異常進行處理的方法,因此mian方法也不能處理此異常,于是異常又被拋出到JVM中
  • JVM接受到異常后,采取了默認的處理措施,停止運行程序,于是后面的這個syso語句沒有執行。

異常也是對象,上述例子中異常對象的描述類是ArithmeticException,它是用來描述數學中算數問題的 異常類。比如還有常見的空指針異常描述類NullPointerException。

二、異常的繼承體系

Throwable類是所有異常和錯誤的父類

  • Error 錯誤

  • Exception 異常

    錯誤:程序出現了嚴重的問題,不修改代碼,根本不能運行,人得了非典,艾滋,癌

    異常:程序出現了比較輕的問題,處理掉之后,繼續運行,人得了闌尾炎,感冒

Exception類是所有異常的父類

  • 非RuntimeException
  • RuntimeException

Throwable中的方法:

  • String toString()重寫Object類的方法,異常信息的詳細描述?
  • String getMessage() 返回異常信息的簡短描述
  • void printStackTrace() 異常信息輸出到控制臺

三、異常的兩種處理方式

  1. 直接處理掉異常

    demo:

    try{
      嘗試捕獲異常的代碼
    }catch(異常類 異常變量){
      異常處理代碼
    }
    
  2. 第二種處理方式就是拋出異常

    • throw 手動拋出異常,后面寫的是new異常的對象,寫在方法中
    • throws 方法聲明拋出異常,后面寫的是異常類,寫在方法的聲明上

    demo:

    /*
      異常第二種處理方式,拋出異常
      throw throws的用法
    
      ExceptionDemo2.java:21: 錯誤: 未報告的異常錯誤Exception; 必須對其進行捕獲或聲明
      以便拋出
          throw new Exception();
      方法中,有異常拋出,但是沒有處理過,因此編譯失敗
      異常的編譯提示,是Java編譯時的最后提示
    */
    
    class ExceptionDemo2 
    {
     public static void main(String[] args) throws Exception
     {
         //System.out.println("Hello World!");
         //main中調用了method方法,方法拋出了異常
         //main有2個選擇方法,一個是try...catch
         //另外一個是,異常我也不處理,交給我的調用者處理
         method(-5);
     }
     /*
        如果方法的參數小于0
        程序出現異常,如果參數大于0 ,程序是正常的
        方法自己,不想處理這個異常,把異常交給調用者處理
        在方法聲明上,拋出異常,聲明出來有異常,交給調用者
        throws 異常類
     */
     public static void method(int x)throws Exception{
        if(x < 0)
            //程序出現了問題
            //手動拋出異常
            throw new Exception("程序出現了異常了");
         
         else
             System.out.println("程序正常");
     }
    }
    

四、多層異常的處理

demo

/*
  多層的異常處理方法調用
*/

class ExceptionDemo3 
{
    public static void main(String[] args) 
    {
        //System.out.println("Hello World!");
        try{
        methodA();
        }catch(Exception e){
        
        }
    }

    public static void methodA()throws Exception{
       methodB();
    }

    public static void methodB()throws Exception{
        methodC();
    }

    public static void methodC()throws Exception{
       throw new Exception();
    }
}

五、finally代碼塊

  • finally可以跟隨try出現,也可以跟隨try...catch出現
  • finally代碼塊中的程序,必須要運行
  • finally實際的開發意義,釋放資源

demo

/*
   finally代碼塊
   一定要執行
*/

class ExceptionDemo4 
{
    public static void main(String[] args) 
    {
        try{
        method(1);
        }catch(Exception e){
           e.printStackTrace();
        }finally{
            System.out.println("這里的程序必須執行");
        }
    }

    public static void method(int x)throws Exception{
       if(x == 1)
           throw new Exception("異常了!!");
       else
           System.out.println("程序正常了");
    }
}

一個finally的特例:

/*
demo:true or false
*/
class ExceptionDemo5{
  public static void main(String[] args){
    System.out.println(method());
  }
  public static boolean method(){
    
    try{
      return false;
    }catch(Exception e){
      
    }finally{
      return true;
    }
  }
}
//結果:true


/*
demo2:2 or 10
開發中,不要再try catch中寫return
*/
class ExceptionDemo6{
  public static void main(String[] args){
    System.out.println(method());
  }
  public static int method(){
    int i = 1;
    try{
      return ++i;
    }catch(Exception e){
      return 100;
    }finally{
       i=10;
    }
  }
}
//結果:2

六、編譯時期的異常

調用一個方法,這個方法拋出一個異常,此時調用者必須處理異常,否則編譯失敗。

Demo

/*
   編譯時期的異常 
*/
class ExceptionDemo2{
    public static void main(String[] args){
        System.out.printf("hello wordl");
        method();
    }

    public static void method() throws Exception{}
}

結果如下:

ExceptionDemo2.java:10: 錯誤: 未報告的異常錯誤Exception; 必須對其進行捕獲或聲明
以便拋出
        method();
              ^
1 個錯誤

改進,加上try catch對異常進行處理,錯誤提示消失。

/*
   編譯時期的異常 
*/

class ExceptionDemo2{
    public static void main(String[] args){
        System.out.printf("hello wordl");
        try{
        method();
        }catch(Exception e){}
    }

    public static void method() throws Exception{}
}

七、運行時期的異常

運行時期的異常一旦發生了,后面的所有程序都不會接著往下執行,所以設計運行時期的異常的初衷就很明顯了,這個異常就是讓開發人員看的,發生運行異常,就必須去修改原代碼,而不是去處理異常。

Demo

/*
  運行時期的異常的特點
*/
class ExceptionDemo3{
    public static void main(String[] args){
        //調用者不知道方法會出現異常,所以就不用處理
        //這種時候,需要修改代碼,而不需要處理
        method();
    }

    public static  void method(){
        //手動拋出一個異常

        throw new RuntimeException();
    }
}

Demo2

/*
  要求:計算正方形面積,邊長的平方
  定義方法:求面積,返回結果
*/
class ExceptionDemo4{
    public static void main(String[] args){
        
        System.out.println(method(-8));
    }

    public static  int method(int num){
        if(num <= 0){
            //邊長不合法,沒有必要計算
            throw new RuntimeException("<= 0");
        }
        return num * num;
    }
}

常見的運行時期的異常:

異常對象 實際含義
IndexOutOfBoundsException 越界(字符串,和數組)
NullPointerException 空指針
ClassCastException 類型轉換異常
NoSuchElementException 沒有元素被取出
IllegalArgumentException 無效參數異常

八、自定義異常

Java中異常體系,將很多的情況都做了異常封裝,但是實際的開發中,不可能把所有的異常都描述完畢,需要自定義的異常,用來描述自己程序中可能發生的異常。

自定義異常步驟:

  1. 定義類,后綴名Exception繼承Exception類,或者繼承RuntimeException
  2. 異常信息,自定義的異常類的構造方法,把異常信息使用super傳遞到父類

注意:只有異常類,才具備可拋性 throw new 異常體系的類

通過剛才案例:

  1. 如果一個方法中,拋出多個異常,必須要throws聲明多個異常(運行時起除外)
  2. 調用者,使用多個catch進行異常的捕獲
  3. 多個catch中,最大(繼承關系)的父類,寫在最后面,否則編譯失敗

Demo

package exceptions;

/*
 * 自定義異常
 */

//負數異常
class FuShuException extends Exception{
     FuShuException(){}

     FuShuException(String info){
        super(info);
    }
}

//0異常
class ZeroException extends Exception{
    ZeroException(){}

    ZeroException(String message){
        super(message);
    }
}


public class ExceptionDemo5 {
    public static void main(String[] args) {
        try{
        getArea(0);
        }catch(FuShuException e){ //多異常,就多catch,范圍越大的往后寫
            e.printStackTrace();
        }catch(ZeroException e){
             e.printStackTrace();
        }
    }
    public static int getArea(int num) throws FuShuException,ZeroException{
        if(num < 0){
            throw new FuShuException("邊長是負數");
        }
        else if(num == 0){
             throw new ZeroException("邊長為0");
        }

        return (int)Math.pow(num,2);
    }
}

九、繼承異常

前提:子類重寫父類的方法

  • 父類的方法拋出了異常,子類重寫后,異常:父類拋異常,子類可拋可不拋,但是,如果子類拋,不能拋出比父類還大的異常
  • 父類的方法不拋異常,子類重寫后,子類不能拋出異常。如果子類重寫的方法中,調用了一個拋異常的方法,子類別無選擇,只能try...catch處理異常

demo

package exceptions;

/*
 * 自定義異常
 * 1.父類方法拋異常,子類重寫后可拋可不拋,若是拋,則要小于父類(前提是子類重寫了父類方法)
 * 2.父類方法不拋異常,子類也不能拋,若是子類調用的方法拋了異常,子類只能try catch
 */

//A是父類異常類
class AException extends Exception{

}
//B繼承A
class BException extends AException{
    
}
//C和A是兄弟類
class CException extends Exception{
    
}

class Zi extends Fu{
    public void show() throws BException{}
}

class Fu{
    public void show() throws AException{}  
}

public class ExceptionDemo6 {
    public static void main(String[] args) throws AException{
        Fu f = new Zi();
       
          f.show();
    }
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 通俗編程——白話JAVA異常機制 - 代碼之道,編程之法 - 博客頻道 - CSDN.NEThttp://blog...
    葡萄喃喃囈語閱讀 3,202評論 0 25
  • Java異常類型 所有異常類型都是Throwable的子類,Throwable把異常分成兩個不同分支的子類Erro...
    予別她閱讀 961評論 0 2
  • 一、多態 1. 概述 理解:多態可以理解為事物存在的多種體(表)現形態。例如:動物中的貓和狗。貓這個對象對應的是貓...
    陳凱冰閱讀 344評論 0 1
  • 今天下午飯都沒有吃飽就把飯給倒了,因為下午吃飯時間只有半小時,而我們在四樓上班,食堂離我們又遠,走到食堂都5:10...
    掌心日記閱讀 412評論 0 0
  • 大偉滿足了若希對男人所有的幻想。知情識趣,浪漫體貼。明知他永遠不缺女人,還是愿意默默守候,奢望有天能感動他。 這天...
    煙行閱讀 292評論 0 4