2.8Java異常

1.定義:
異常:是在運行時期發生的不正常情況。
異常類:在java中用類的形式對不正常情況進行了描述和封裝對象。描述不正常的情況的類,就稱爲異常類

以前正常流程代碼和問題處理代碼相結合,
現在將正常流程代碼和問題處理代碼分離,提高閱讀性。

2.體系:
問題一多,類就越多。
將其共性向上抽取,形成體系:

Throwable: 父類,無論是error,還是異常,都是問題,問題發生就可以拋出,讓調用者知道並處理。

該體系的特點:就在於Throwable及其所有的子類都具有可拋性。子類的後綴名都是用其父類名作爲後綴,閱讀性很強。
可拋性的體現:通過兩個關鍵字來體現:thorws,throw。凡是可以被這兩個關鍵字所操作的類和對象都具有可拋性。

3.問題的分類:
最終問題就分成了兩大類:

1.一般不可處理。Error
特點:是由jvm拋出的嚴重性的問題。
這種問題發生一般不針對性處理。直接修改程序。

2.可以處理的。Exception

例子:

class  ExceptionDemo1
{
    public static void main(String[] args) 
    {

    }

    public static void sleep(int time)
    {
        if(time<0)
        {
            拋出 new FuTime();    //就代表着時間爲負的情況,這個對象中會包含着問題的名稱,信息,位置等信息。
        }
        System.out.println(time);
    }
}

class FuTime    //異常類
{

}

4.異常原理:
異常原理

例子:

/*
異常原理

*/
class Demo
{
     int method(int[] arr, int index)
    {
 /*     //②可以自己產生異常

         if(arr == null)    
                throw new NullPointerException("數組引用不能爲空");

         if(index >= arr.length)      
        {
            throw new ArrayIndexOutOfBoundsException("數組角標越界");
         }
*/



        return arr[index];     //①默認會進行異常對象封裝:throw new ArrayIndexOutOfBoundsException(index)
                                                                                //程序終止,下面的代碼不再執行        
    }
    }

class ExceptionDemo2 
{
    public static void main(String[] args) 
    {
        int[] arr = new int[3];
        Demo d = new Demo();
        int num = d.method(null,3);         //異常拋出到這裏,然後主函數又丟給虛擬機。虛擬機執行異常處理機制,把異常信息打印。
                                                    //可惜用戶看不懂
                                                    //程序終止,下面的代碼不再執行
        System.out.println(num);
    }

}

5.自定義異常: 聲明 throws

注意點:如果讓一個類稱爲異常類,必須要繼承異常體系,因爲只有成爲異常體系的子類,纔有資格具備可拋性。
才能被兩個關鍵字所操作,throws,throw

異常的分類:

1.編譯時被檢測異常:Exception和其子類都是,除了特殊子類RuntimeException體系。(需要異常聲明throws處理)
如:自定義異常FuShuIndexException

這種問題一旦出現,希望在編譯時就進行檢查,讓這種問題有對應的處理方式。


2.編譯時不檢查異常:Exception的特殊子類RuntimeException及其子類。(它們在編譯時不需要異常聲明處理)
如:數組越界異常ArrayIndexOutOfBoundsException,空指針異常NullPointerException等。(遇到較多)

這種問題的發生,無法讓功能繼續,運算無法進行,更多是因爲調用者的原因導致的或者引發了內部狀態的改變導致的。
那麼這種問題一般不處理,直接編譯通過,在運行時,讓調用者調用時的程序強制停止,讓調用者對代碼進行修正。

所以自定義異常時,要麼繼承Exception,要麼繼承RuntimeException。

throws 和throw的區別:

1.throws 使用在函數上
    throw 使用在函數內

2.throws拋出的是異常類,可以拋出多個,用逗號隔開
    throw 拋出的是異常對象。

例子:

/*
自定義異常:聲明 throws

舉例:對於負數角
標這種異常java中沒有定義過。
那麼,就按照java異常的創建思想,面向對象,將負數角標進行自定義描述,並封裝成異常類。

java先檢查語法錯誤,纔會檢查邏輯錯誤。異常最後報錯。
*/
class FuShuIndexException extends Exception
{
    FuShuIndexException()
    {
    }
        FuShuIndexException(String msg)
    {
                super(msg);          //調用的父類的構造方法。
    }
}

class Demo
{
    int method (int[] arr, int index) throws FuShuIndexException   //要在函數聲明後添加   異常聲明
    {
        if(index <0)
            throw new FuShuIndexException("數組角標負數異常");     //錯誤:未報告的異常錯誤FuShuIndex; 必須對其進行 捕獲 或 聲明 以便拋
        return arr[index];  
    }
}


class ExceptionDemo3 
{
    public static void main(String[] args) throws FuShuIndexException   //添加 異常聲明
    {
        int[] arr = new int[3];
        Demo d = new Demo();
        int i = d.method(arr,-1);    //使用了異常聲明函數,也必須在函數上添加 異常聲明
        System.out.println(i);
    }
}

6.異常自定義處理: 捕捉

這是可以對異常進行 針對性 處理方式。

具體格式:

try
{
    //需要被檢測異常的代碼
}
catch(異常類 變量)  //接收發生異常的對象
{
    //處理異常的代碼
}

finally
{
    //一定會被執行的代碼
}
這個問題如果自己不能處理,就用throws

如果自己可以處理,就用try

例子:

class FuShuIndexException extends Exception
{
    FuShuIndexException()
    {
    }

    FuShuIndexException(String msg)
    {
        super(msg);
    }
}

class Demo 
{
    int method(int[] arr, int index)   throws FuShuIndexException,NullPointerException   //如果拋出了多個異常,則需要多catch
    {
        if(arr == null)
            throw new NullPointerException();
        if(index <0)
            throw new FuShuIndexException("數組角標爲負數!");
        return arr[index];
    }
}


class  ExceptionDemo4
{
    public static void main(String[] args)     //如果異常自己解決不了,就拋出去throws,給虛擬機執行.printStackTrace()。
    {
        int[] arr = new int[3];

        Demo d = new Demo();    
        try
        {
                int i = d.method(null,0);        //異常拋在這裏,new FuShuIndexException("數組角標爲負數!");
                System.out.println(i);  

        }
        catch (FuShuIndexException f)     //接收拋來的異常對象,而不是直接給虛擬機了。
                                                                            //FuShuIndexException f = new FuShuIndexException("數組角標爲負數!");
        {


            System.out.println(f.getMessage());       //可以使用異常對象,及其父類的所有方法,打印需要的異常信息
                                                    //輸出異常信息
            System.out.println(f);                 //該對象不是類型和哈希值,(f.toString())異常對象有建立自己的獨特字符串類型(可以該的,其實是默認加了toString()方法)。
                                                    //輸出異常類名 + 異常信息
            f.printStackTrace();       //輸出異常類名 + 異常信息 ,及其追蹤輸出。 注意返回值是空類型,不要直接打印。
                                                    //jvm默認的異常處理機制就是調用異常對象的這個方法。




            System.out.println("負數角標異常!");      //自行處理方式
        } 

/*      catch()      //多異常多catch
        {

        }*/

        catch(Exception e)    //如果爲了檢測其他異常,父類的catch應該放最後,因爲是按順序檢測。而所有異常對象都屬於Exception。
                                                //多catch時面試會問。
        {                                           
                e.printStackTrace();
        }
        System.out.println("over");     //程序繼續運行
    }
}

//通常建立日誌文件用第三方工具,如 log4j(log for java)

多catch情況:父類的catch應該放最後,因爲是按順序檢測。而所有異常對象都屬於Exception。

7.異常處理原則:

1.函數內部如果拋出需要檢測的異常,那麼函數上必須要聲明。
    否者必須在函數內用trycatch捕捉,否者編譯失敗。
2.如果調用到了聲明異常的函數,要麼trycatch,要麼throws,否者編譯失敗。
3.功能內部可以解決,用catch.
解決不了,用throws告訴調用者,由調用者解決。
4.一個功能如果拋出了多個異常,那麼調用時,必須對應多個catch進行針對性的處理。
內部有幾個需要檢測的異常,就拋幾個異常。拋出幾個,就catch幾個。

8.finally代碼塊:
1)作用舉例:

連接數據庫。
查詢。      Exception
關閉連接。  一定要執行,放在finally代碼塊裏。

2)代碼塊組合:

1.try catch finally
2.try catch(對個)    當沒有必要資源需要釋放時,可以不用定義finally

3.try finallycatch就沒有處理,所以還是要在函數上throws聲明異常來處理。

用處:異常先不處理,但是資源得關掉。

void show() throws Exception
{
        try
        {
                //開啓資源
                throw new Exception();
                //這裏無法關閉資源,因爲執行不到
        }
        finally
        {
                //關閉資源
        }
}

3)例子:

class Demo
{
    int show(int index)
    {
        if(index < 0)
            throw new ArrayIndexOutOfBoundsException("越界了!");
        int[] arr = new int[3];
        return arr[index];
    }
}


class  ExceptionDemo5
{
    public static void main(String[] args) 
    {
        Demo d = new Demo();


        try
        {
             int num = d.show(-3);
            System.out.println(num);
        }
        catch (ArrayIndexOutOfBoundsException e)
        {
                System.out.println(e.toString());
                return;                  //如果System.exit(0); 推出jvm,這時finally不執行
        }
        finally
        {
                System.out.println("finally");     //函數結束,也會執行
        }


        System.out.println("over");    //函數如果提前結束,不會執行
    }
}

9.異常的應用:

/*
異常的應用:   異常轉換:不要有什麼異常就拋出什麼異常,要看調用者能否處理。

void addData(Data d)    throws  Exception         //不拋出數據庫異常,因爲調用者不懂數據庫。
                                                                                        //進行異常轉換,拋出調用者可以處理的異常。
{
    連接數據庫。
    try
    {
        添加數據。出現異常 SQLException();
    }
    catch(SQLException e)
    {
        處理數據庫異常。
        throws new Exception("數據沒有添加成功");   //可以自定義異常拋出
    }
    finally
    {
        關閉數據庫。
    }

}






畢老師用電腦上課。

問題領域中涉及兩個對象。
畢老師,對象。

分析其中的問題:

比如電腦藍屏,冒煙了。

*/

class LanPingException extends Exception
{
        LanPingException(String msg)
    {
            super(msg); 
    }
}

class MaoYanException extends Exception
{
        MaoYanException(String msg)
            {
                super(msg);
        }
}

class  prelectStop extends Exception
{
        prelectStop(String msg)
        {
                super(msg);
        }
}

class Computer 
{
    private int state = 2;
    void run() throws LanPingException,MaoYanException
    {
        if(state == 1)
            throw new LanPingException("電腦藍屏了!");
        if(state == 2)
            throw new MaoYanException("電腦冒煙了!");

        System.out.println("電腦運行");
    }

    void reset()
    {
        state = 0;
        System.out.println("電腦重啓");
    }
}

class Teacher
{
    private String name;
    private Computer comp;
    Teacher(String name)
    {
        this.name = name;
        comp = new Computer();
    }

    void prelect()   throws prelectStop  //  throws MaoYanException   //老師講課拋出電腦冒煙,不合理
    {
        try
        {
            comp.run();
            System.out.println("講課");
        }
        catch (LanPingException e)
        {
                System.out.println(e.getMessage());
                comp.reset();                              //預處理,可以自己處理,所以才設置爲編譯時檢測異常Exception,而不是運行時異常RuntimeException
                prelect();
        }
        catch (MaoYanException e)
        {
                System.out.println(e.getMessage());
                test();
                //可以對電腦進行維修,但是不傳給調用者,因爲他也處理不了
                //throw e;         //冒煙異常處理不了,返回給調用者在方法聲明中標識出來。
                throw new prelectStop("課程進度無法完成!原因:" + e.getMessage());        //返回調用者可以處理的異常,異常進行了轉換
        }



    }

    void test()
    {
        System.out.println("做練習");
    }
}


class ExceptionDemo6 
{
    public static void main(String[] args) 
    {
        Teacher t= new Teacher("畢老師");

        try
        {
            t.prelect();
        }
        catch (prelectStop e)
        {
                System.out.println(e.getMessage());
                System.out.println("換人");

        }

    }
}

10.異常的注意事項:
1.子類在覆蓋父類方法時,父類方法如果拋出了異常,那麼子類的方法只能拋出父類的異常或者該異常的子類,也可以不拋。
2.如果父類拋出多個異常,那麼子類只能拋出父類異常的子集。

簡單點說:如果父類的方法沒有拋出異常,那麼子類覆蓋時絕對不能拋。(爸爸夠壞了,兒子不能更壞了)

這時如果子類還是使用了異常,只能try,不能拋。
/*
原因:如果在方法2中傳入了父類的對象,並trycatch了父類的方法1,這時catch中是父類的異常類型。如果有一個子類覆蓋了父類的
方法1,這時如果方法2中傳的是子類的對象(向上轉型),則先調用的是子類中覆蓋的方法,這時catch中的異常類型只有是父類的異常
或者子類纔不會出現問題。
*/
//舉例:
class A extends Exception
{
}

class B extends A
{
}

class C extends Exception
{
}


class Fu
{
    void show() throws A
        {}
}

class Zi extends Fu
{
    void show() throws B    //這時應該爲A或者B
    {}
}

class Test
{
    void method(Fu f)
    {
            try
            {
                f.show();
            }
            catch(A a)     
            {
            }
    }
}

class ExceptionDemo7 
{
    public static void main(String[] args) 
    {
        Test t = new Test();
//      t.method(new Fu());
        t.method(new Zi());   
    }
}
發佈了36 篇原創文章 · 獲贊 0 · 訪問量 4577
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章