上海傳智播客JAVASE_day12學習筆記

異常

1、什麼是異常

就是程序在運行期間出現的一些不正常的現象。

2、異常的體現

//異常的體現

class Demo

{

       public static void main(String[] args)

       {

              int[] arr = new int[4];

              //arr[4] = 100;  //ArrayIndexOutOfBoundsException 數組下標越界

 

              int[] arr2 = newint[1024*1024*200];  //OutOfMemoryError  內存不足

       }

}

 

3、異常的分類:

錯誤:Error

如果程序在運行的期間發生錯誤,這時我們使用程序人,或者我們調用了別人的程序發生了錯誤,這時只要不是我們自己的程序導致,我們都不做任何的修改。

針對運行時期的錯誤,我們不做任何預先的處理。而讓錯誤發生之後,誰寫的代碼,就讓當事人去修改。

異常:Exception

異常在程序中,需要提前給出響應的處理。當我們在使用別人的程序,或者自己寫的程序,我們已經明確知道程序中有異常,那麼在編寫代碼的時候,就需要對這些一行問題提前給出處理方案。

 

4、異常的發生過程:  ★★★★★

5、異常的應用   ★★★★★

 

class Demo4

{

       //根據下標獲取數組中的值

       /*

              當我們在定義功能的時候,如果我們的功能要接收調用者傳遞的參數

              這時就要對調用者傳遞的參數做合法的驗證

              只有驗證通過之後才能去使用調用者傳遞的參數

       */

       public static intgetValue( int[] arr , int index )

       {

              //對調用者傳遞進來的參數做判斷

              /*

                     在運行程序的時候發生空指針異常之後,

                     這時肯定是在發生的地方使用了一個引用變量,

                     但這個引用變量不指向任何一個對象。

                     這樣仍然在使用這個引用去訪問對象中的內容

              */

              //對調用者傳遞引用變量進行合法驗證

              if( arr == null )

              {

                     //判斷成立說明當前的arr引用不指向任何一個數組

                     throw newNullPointerException("傳遞的數組爲null");

              }

             

              //對下標進行驗證

              if( !(index >=0 && index <= arr.length-1) )

              {

                     //這裏已經檢測到調用者傳遞的下標不再數組的範圍內。

                     //應該手動的告訴調用傳遞的下標非法了

                     //可以使用異常的方式告訴調用者傳遞數據非法了

                     throw newArrayIndexOutOfBoundsException(index+"不在數組的下標範圍內!!!");

              }

                           

 

              returnarr[index];

       }

 

       public static voidmain(String[] args)

       {

              int[] arr ={4,1,2,6,5,9,0};

 

              int value =getValue(null,10);

             

              System.out.println("value="+value);

              System.out.println("over");

       }

}

 

 

6、查看的技巧

當知道類名不知道包名的之後可以在api搜索,如果知道包名可以直接選擇包來找對應的類。

  當前的找到這個名稱到底是類還是接口,並且會告訴我們當前這個類所屬的包

 

 

 

當這個類的繼承體系

 

 

當前這個類實現的接口

 

 

   當前這個類的定義格式。當看到是abstract關鍵字說明當前這個類抽象類,這個類不能創建對象。

如果看到了final,就必須反映到這個類不能被繼承

 

 

 

   當前這個類的描述信息,其中會告訴我們這個類的簡單使用和這個類到底是在解決什麼問題。

   這個類對外公開的構造方法。

 

   當前類中定義的普通的方法

 

 當前這個類從父類中繼承到的方法

 

 

7、自定義異常   ★★★★★

 

在異常應用練習中,我們檢測到了問題之後,我們使用api中提供的異常類,然後創建對象,把異常信息拋給調用者。在查看api的時候,發生我們拋出的那些異常問題對象都是api中提高好的類。

既然api中使用類來描述程序在運行時的一種不正常現象。那麼就說明我們也可以自己來定義類,用自己的類來描述某些我們自己想表達的異常信息。

 

 

 

在實現自己定義的異常時,我們先寫了一個類,想把它當作異常類。但是編譯報錯了。它說我們定義的類無法轉成Throwable。

我們就必須去查看Throwable是什麼東西?

在api中找到了Throwable這個類:

發現Throwable有2個子類Error和Exception

Throwable類是 Java 語言中所有錯誤或異常的超類。只有當對象是此類(或其子類之一)的實例時,才能通過 Java 虛擬機或者 Java throw語句拋出。

 

 

將我們的類定義成了Throwable的子類

 

 

 

 

 

當我們把自己定義的異常類,繼承了Throwable之後,再次編譯,告訴我們自己寫的類沒有報告。並且告訴我們的解決方案是:

1、捕獲

2、聲明

可是我們在對數組進行處理的時候,我們也手動使用了異常。但是並沒有告訴我們說要報告,捕獲,聲明,爲什麼自己寫的就要捕獲或者聲明呢?

我們開始分析空指針異常和數組下標越界異常,發生它們都有共同的父類RuntimeException。這時我們去找找看RuntimeException類是什麼東西?

RuntimeException是那些可能在 Java 虛擬機正常運行期間拋出的異常的超類。

 

當我們在程序中要想拋出異常,並且這個異常是程序正常運行期間需要拋出的,那麼我們定義的這個異常就必須爲RuntimeException的子類。

上面問題的解決,讓我們定義NoAgeException繼承RuntimeException即可

 

 

 

 

 

解決自定義異常構造方法不匹配問題,以及如何顯示自己指定的異常信息

 

總結:自定義異常如何書寫:

1、定義一個類   建議定義異常類的時候類名最後書寫Exception

2、要讓自己定義的這個異常類繼承Throwable下的某個子類。 

如果是在運行時期纔會發生的異常,就繼承RuntimeException

3、在自己定義的類中書寫有參數和無參數的構造方法,然後在構造方法中書寫super語句,把異常信息傳遞父類去處理。

 

 

8、異常的分類  

異常分爲:Error和Exception

重點學習Exception:

 

8.1、Exception   ★★★★★

Exception類它是異常類,它所有編譯時期的異常類的超類。如果在程序我們使用Exception異常類,那麼在程序編譯的時期,編譯器就會檢測當前的異常有沒有提前給處理方案,如果當前的程序沒有給出提前的處理方案,這個程序在編譯時期無法通過。

              if( x > 0 )

              {

                     /*

                            在show方法中我們使用Exception異常,而這個異常屬於編譯時期編譯器會檢測的異常

                            而我們在這裏使用了異常,卻沒有對這個異常進行處理,那麼這時編譯器檢測到沒有處理這個問題

                            它就無法編譯通過。

 

                            當我們是功能的定義者時,在定義功能的時候,如果我們的程序有問題(異常)發生,並且我們需要

                            功能的調用者提前就知道他調用的我們的程序中的問題,並且要求調用者提前就想好如何去處理這個問題,

                            如果調用者他不給出任何處理方案,就不讓程序編譯通過,這時就可以使用編譯時期。

 

                            當我們定義的功能中使用編譯時期異常,這時如果這個異常又要暴漏給調用者,這時

                            需要在我們定義的功能上使用throws關鍵字對功能中的異常進行聲明

 

 

                            聲明的目的是把功能中的異常報告給調用者,要求調用者提前給處理方案。

 

 

                            編譯時期異常,目的是讓程序的調用者知道問題的存在,並在在使用這個已經有問題的功能之前

                            就想好處理方案。

 

                     */

                     throw newException("x大於零了");

 

 

8.2、RumtimeException  ★★★★★

              if( x < 0 )

              {

                     /*

                            運行時期異常:

                                   當在定義功能的時候,如果程序中檢測到了問題,但這個問題不需要調用者提前給處理方案,

                                   這時就可以不用拋出編譯時期異常,那麼在編譯代碼的時候,編譯器就不會檢測這個問題

                                   編譯正常通過,當程序真正運行起來的時候,問題發生了,這個時候這個問題就會直接

                                   拋給了調用者。那麼由於沒有在方法上對這個問題進行聲明,調用者在調用的時候也不知道,

                                   那麼調用就不會提前給處理方案,就會導致調用者的程序停止運行。

 

                     */

                     throw newRuntimeException("x小於零了");

              }

 

編譯時期和運行時期異常:

編譯時期異常目的是讓在程序編譯時期就把問題暴漏出來,讓使用這提前想好問題的處理方案,並在代碼中給響應的處理方案。

運行時期異常,在編譯時期不需要編譯檢測,那麼問題在編譯時期不會暴漏出來,使用者就不會知道,也不會給處理方案,在運行期間,問題發生程序就停止了。

 

9、異常處理:   ★★★★★

Java中的異常處理是通過捕獲或者聲明來處理。

9.1、聲明

當在程序中有異常發生,這時我們可以有2種處理方案,最簡單的就是在方法上使用throws關鍵字把這個問題聲明出去。

 

throws關鍵字主要用在方法上,用於聲明方法中使用throw關鍵字拋出的異常(編譯時期異常)。

 

 

9.2、捕獲

聲明是在方法上把異常報告給調用者。捕獲是在方法中把這個異常抓住。不讓這個問題暴漏出去。

捕獲異常的格式:

try

{

//在try代碼塊中書寫可能發生異常的問題代碼

}

catch(  發生的異常名字  變量名 )

{

對捕獲到的異常進行處理的代碼

}

 

class Demo5

{

       public static void show( int x ) throwsException  //聲明異常

       {

              if( x < 0 )

              {

                    

                     throw newRuntimeException("x小於零了");

              }

 

              if( x > 0 )

              {

                    

                     throw new Exception("x大於零了");

              }

              System.out.println("x="+x);

       }

 

       public static void main(String[] args)

       {

              try

              {

                     show( 1 );  //這裏發生了異常,導致它下面的語句不會在執行

                     System.out.println("try代碼塊執行完了");

              }

              catch ( Exception e)   //這裏負責捕獲try中發生的異常

              {

                     //書寫異常的處理代碼

                     System.out.println("異常被抓了,我就不處理");

              }

 

              System.out.println("mainover");

       }

}

 

9.3、聲明和捕獲的區別

聲明主要用在方法上,主要功能是把方法中的異常聲明給調用者。方法中沒有異常,也可以在方法上聲明異常。聲明的目的只有一個,就是把異常報告給調用者。

捕獲:主要用在方法中,對方法中出現的問題在方法中直接捕獲掉,把問題在方法中直接處理完成。

 

10、異常的練習

/*

       需求:

              定義功能,實現計算矩形的面積。

              要求對矩形的長和寬進行合法性的驗證,同時使用自定義異常來處理

      

       思路:

             

              矩形是幾何圖形中的一類事物,既然是個事物,就可以使用Java的類來描述。

              分析矩形都有那些特點:

                     屬性:

                            長

                            寬

                     功能:

                            計算面積和周長

                            面積:長*寬

                            周長:(長+寬) * 2

             

              就需要定義一個類,來描述矩形這個事物

              長和寬可以是事物的屬性,使用類中的成員變量來描述,要使用非靜態的成員變量來描述

              功能是通過方法來體現。在功能中定義計算面積和周長的代碼。

              建議面積單獨定義一個功能,周長單獨定義一個功能

              矩形這類事物,在一創建對象就應該明確其長和寬。就需要在這個類中定義構造方法,

              用於明確創建矩形對象時傳遞的長和寬

 

 

              要求對矩形的長和寬進行合法驗證,結合事實,矩形的長和寬不能負數。

              同時還要使用自定義異常來表示長或者寬的非法

*/

//自定義異常,主要處理矩形的寬非法

classNoWidthException extends Exception

{

       NoWidthException()

       {

       }

       NoWidthException(String s)

       {

              super(s);

       }

}

//自定義異常,主要處理矩形的高非法

classNoHeightException extends RuntimeException

{

       NoHeightException()

       {

       }

       NoHeightException(String s)

       {

              super(s);

       }

}

 

 

//定義類,描述矩形

class Rec

{

       private double  width; //寬

       private double  height; //高

 

       //定義構造方法,在創建矩形對象的時候要求明確高和寬

       Rec( double width , double height ) throws NoWidthException

       {

              //這裏需要對width和height進行驗證

              if( width <= 0 )

              {

                     //驗證不合法之後需要使用異常通知調用者

                     throw newNoWidthException("傳遞的寬必須大於零");

              }

 

              if( height <= 0 )

              {

                     //驗證不合法之後需要使用異常通知調用者

                     throw newNoHeightException("傳遞的高非法");

              }

 

              this.width = width;

              this.height = height;

       }

 

       //計算面積

       double getArea()

       {

              double area = width * height;

              return area;

       }

}

classExceptionTest

{

       public static void main(String[] args)

       {

              try

              {

                     Rec r = new Rec(-2,-3);

                     double area = r.getArea();

                     System.out.println("area="+area);

              }

              catch (  NoWidthException e )

              {

                     System.out.println("異常啦");

                     e.printStackTrace() ;

                     System.out.println(e.toString());   

              }

             

       }

}

 

總結:

什麼時候使用捕獲,什麼時候使用聲明:

 

首先明確自己到底是功能的定義者還是功能的調用者。

 

如果我們是功能的定義者,在我們的功能中有異常發生,而這個異常不需要告訴給調用者,這時就要在自己的功能中必須把這個捕獲調用。

如果這個問題需要告訴調用者,這時就可以在方法上使用throws關鍵字把異常聲明出去。

 

功能的調用者:我們調用別人的程序,由於別人的程序發生了問題,自己在調用的時候,就需要提前給出處理方案,而Java對異常的處理方案僅有2種,

捕獲和聲明。如果這個問題在我們自己的程序能夠處理掉就不要再使用聲明,而發自己依然要把這個問題往外暴漏,那麼就可以使用聲明

 

把這種異常不斷的往出聲明,這種現象稱爲異常鏈。

 

11、捕獲的細節

在定義一個功能的時候,如果功能中拋出了多個異常,這時可以在方法上同時聲明這些異常。

       在程序中如果發生了異常導致異常下面的代碼無法執行。

       這時我們程序卻有部分代碼要求不管程序有什麼問題都要執行。

       Java提供瞭解決方案:

              try

              {

                     可能發生異常的代碼

              }

              catch()

              {

                     處理異常的代碼

              }

              finally

              {

                     一定會被執行的代碼

                     不管發生什麼問題,這裏的代碼一定會被執行

              }

              finally代碼塊主要是使用在Java操作Java以外的數據時,要求不管發生什麼問題,都要和Java以外的數據

              連接斷開。這時就可以把這段斷開連接的代碼書寫finally中。

 

              try

              {

             

              }

              finally

              {

              }

              這種組合僅僅是爲了讓finally中的代碼執行而已。

              異常完全沒有被捕獲

 

              try

              {

              }

              catch()

              {

              }

              catch()

              {

              }

              catch()

              {

              }

              ...

 

              finally

              {

             

              }

 

 

 

 

*/

 

 

class Demo8

{

       static void show( int x) throws Exception

       {

              if( x == 0 )

              {

                     throw newException("異常啦");

              }

       }

 

       public static voidmain(String[] args)  throws Exception

       {

              try

              {

                     show(0);

              }

              catch (RuntimeException e )

              {

                     System.out.println("異常被捕獲了");

              }

              finally

              {

                     System.out.println("必須執行代碼");

              }

 

       }

}

 

 

 

 

 

 

12、異常的細節

在繼承中異常的應用:

繼承中有方法的複寫:

1、子類複寫父類的方法時,要求方法的返回值,方法名,參數列表必須一致

2、子類複寫父類的方法,要求子類的方法訪問權限大於等於父類的方法權限

3、靜態只能被靜態複寫

4、私有不參與複寫

5、final修飾的方法無法被複寫

6、當父類的方法上沒有聲明任何編譯時期異常,子類在複寫父類的方法時,子類的方法上也不能聲明異常,這時子類中真的都有異常,只能捕獲掉。

7、當父類方法上聲明多個編譯時期異常,子類在複寫父類的方法時,可以聲明這些異常,也可以不聲明任何異常。

8、當父類方法上聲明多個編譯時期異常,子類在複寫父類的方法時,可以聲明父類中多個異常中的子集。

9、當父類方法上有異常聲明時,子類複寫父類方法時,可以聲明父類這個異常的子異常。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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