[size=small][align=center]
-------[url]http://www.itheima.com[/url]java教育訓練、android教育訓練期待與您交流!-------
[/align]
繼續學習面向對象,,,,,
八、異常
1、概述
異常就是程式在運作時出現的不正常情況。
在現實生活中,我們也會遇到很多不正常情況。其中有的是可以解決的,有的則沒有解決必要。比如,電腦的運作速度慢,我們可以清理清理電腦灰塵或對電腦進行垃圾清理。但是,要是,某天不小心将電腦摔地上了,如果幸運,可以修修,如果不幸運,那麼,對不起,就不用修了。
而在java語言中,也有對問題的描述。因為問題也可以歸結為一類事物,那麼,就可以通過java類的形式對問題進行描述,并封裝成對象,也就是說,異常時java對不正常情況進行描述後的對象展現。
問題分為兩種:嚴重的問題:Error 一般不編寫針對性的代碼對其進行處理
非嚴重的問題:Exception 可以針對性處理
而對于這些問題,Error或Exception,都有一些共性内容,如,不正常情況的資訊,引發原因等。是以,将這些共性内容向上抽取就形成了一個體系:
可抛的:Throwable:Error/Exception
2、異常的處理
(1)使用 try - catch - finally 語句進行異常處理
try { 需要被檢測的代碼 }catch( 異常類 變量 ){ 處理異常的代碼(處理方式) }finally{ 一定 會被執行的語句 }
下面用一個例子解釋:
首先定義一個簡單的算數運算,求兩個數的商(不考慮小數)。我們知道,在進行除法運算時,除數不能為0。是以,我們要遵循這個規則。如果出現了除數為0 ,則報異常,否則程式繼續運作。
//定義一個類,用于封裝除法運算
class Div
{
//定義一個方法,用于計算兩個數的商
int div(int x,int y)
{
return x/y;
}
}
class ExceptionDemo
{
public static void main(String[] args)
{
Div d=new Div();
try
{
int x=d.div(4,0);
System.out.println("x="+x);
}
catch (Exception e)//Exception e=new ArithmeticException();
//父類引用指向子類對象 多态的運用
{
System.out.println("除零了,不符合規則");
System.out.println(e.getMessage());//擷取異常的資訊
e.printStackTrace();//列印異常的堆棧的跟蹤資訊
}
System.out.println("over");
}
}
分析一下處理異常的流程:
Div d=new Div();在記憶體中建立對象
int x=d.div(4,0);調用div方法,這時,将4 0傳給x、 y,由于除數為0,不符合規則,虛拟機檢測到異常(java語言自定義的異常),那麼就會出現ArithmeticException,出現了異常,下面的程式就不會執行,将異常轉加給catch語句,讓他對算法異常進行處理。Exception e=new ArithmeticException(); 父類引用指向子類對象 多态的運用
然後,将處理的結果列印出來,這時,異常處理結束。接下來運作異常處理語句外的程式:
System.out.println("over");
(2)将異常聲明(在函數體上聲明異常),也就是抛出異常(throws)
還是上面那個例子。我們知道,x和y的值是使用者輸入的值,那麼,傳入的值就不明确。如果傳入的是符合規則的,程式就不會有什麼問題,但如果傳入的是不合規則的,程式就會停掉。這是我們不希望的。
是以,我們在方法上将可能出現的問題通過關鍵字throws辨別一下,這時編譯時會出現錯誤資訊:必須将異常捕獲或聲明。
一種方式是:在主函數上将異常抛出(這時是将異常抛給了JVM)
int div(int x,int y) throws Exception
一種方式是:在調用方法處捕獲異常。
try - catch
聲明異常便于極高安全性,讓調用者進行處理,不處理則會失敗
(3)多異常處理
顯然,上面的例子隻出現了一個異常。但在實際的開發過程中會出現很多異常。是以,要對多個異常進行處理。
A、也就是在函數上聲明多個可能出現的異常(一般不同異常類用逗号","隔開),這 樣會更具體地處理異常。
如,throws ArithmeticException ,ArrayIndexOutOfBoundException
那麼在處理異常時或捕獲或聲明異常。
B、在函數上聲明幾個,那麼就要有幾個catch塊,且聲明的和處理的要一緻。
要注意:若多個catch中出現繼承關系,父類的異常catch要放在最下面(若放在最上面,出現的異常 父類會處理完,一下的catch塊就不會執行,且報錯)。
C、若捕獲異常,則每個catch語句中要傳入具體的異常類(函數上聲明什麼異常,
catch中就要處理什麼異常),且處理的方法要具體,
不能輸出預設的e.printStackTrace資訊,也不能簡單地列印自定義的異常資訊。
D、當然,在實際開發中不會将出現的異常資訊列印出來,這時會用檔案記錄每個異常發生的時間,情況等資訊,存放在異常日志中。
(4)自定義異常
雖然java語言自定義了很多異常類,但是,在實際開發中我們還是會遇到很多意想不到的異常。這時,就需要我們定義屬于我們自己的異常處理方式。
還是上面那個例子:java異常體系中隻對除數為0的情況定義了異常。但如果除數為負數,這個運算方法也會出錯。為了解決這個問題,就要自定義一個異常類,用于封裝新出現的異常問題。
class FuShuException extends Exception
{
//函數一初始化就會有資訊
FuShuException(String message){
//因為父類中已經定義了顯示異常資訊的方法,是以我們可以直接用
super(message);
}
}
class Div
{
int div(int x,int y) throws FuShuException
{
if (y<=0)
//手動通說關鍵字throw抛出自定義異常對象
throw new FuShuException("除數為負數");
return x/y;
}
}
在抛出自定義異常對象後,我們可以有兩種解決方式:
A、在函數内部使用try - catch處理
B、在函數上聲明
這裡我們直接在函數上聲明了
測試一下:
public static void main(String[] args) throws FuShuException
{
Div d=new Div();
int x=d.div(4,0);
System.out.println("x="+x);
}
3、RuntimeException
RuntimeException是java語言異常體系中比較特殊的一個異常類。為什麼說他特殊呢?我們通過上面的例子解釋一下:
class Div
{
int div(int x,int y) {
if (y==0)
throw new ArithmeticException("除數為0");
return x/y;
}
}
測試一下:
public static void main(String[] args) {
Div d=new Div();
int x=d.div(4,0);
System.out.println("x="+x);
}
這裡我們隻是在函數内部将ArithmeticException這個異常對象抛出去,并沒有在函數上聲明,也沒有在函數内部通過try - catch進行處理,但是在編譯時(javac)并沒有出現出錯提示。這是為什麼呢?
這裡就涉及到ArithmeticException這個異常類的特點,
也就是RuntimeException的特殊之處:
A、若在函數内抛出該異常(這裡所說的異常是RuntimeException異常及RuntimeException 的子類異常:空指針異常、算法異常、角标越界異常等),函數上可不用聲明,編譯能通過
B、若在函數上聲明了該異常,調用者可不用進行處理,編譯一樣通過。
分析一下原因:
我們定義的這個算數方法是提供給使用者使用的。使用者并不知道他們輸入的數值(這裡隻限數值)是怎樣的。是以,輸入合法的數值程式就會正常運作,若輸入的數值不合法,那麼JVM就會檢測出輸入的數值不合法,就會使用自定義的異常方式處理。但不需要将檢測後的處理過程暴露給使用者,隻要将程式停止,那麼使用者就會意識到輸入的數值不合法(不對),進而就會重新輸入。
那麼對于自定義異常,若該異常發生無法再繼續進行運算,就讓自定義異常繼承RuntimeException。
異常分兩種:
編譯時檢測異常(能處理的可辨別出去)
運作時異常(編譯時不被檢測異常RuntimeException及其子類)
4、finally代碼塊
finally代碼塊中定義的是一定要執行的語句,同常用于關閉資源。
處理語句的其他搭配:
try{}catch(){}
try{}catch(){}finally{}
try{}finally{}
5、覆寫時的異常特點
我們知道,一般解決異常要麼在函數上聲明,要麼在函數(方法)内抛出異常對象,要麼在函數内使用try - catch進行處理。而函數(方法)具有覆寫的特點,那麼,當子類覆寫父類的方法時,父類又有異常處理,子類在覆寫時應該注意那麼問題呢?
(1)子類在覆寫父類方法時,如果父類中方法抛出異常,則子類在覆寫時抛出的異常必須是 父類方法抛出的異常或父類抛出異常的子類或者不抛。
(2)當父類方法中抛出多個異常時,子類覆寫父類方法時抛出的異常要能被父類處理(隻能抛 出父類方法中異常的子集)
(3)如果父類或接口的方法中未抛出異常,則子類在覆寫方法時也不可抛出異常。
若此時子類發生了異常則必須進行try處理,且絕對不能抛(沒有接的)
6、異常練習
異常可以将正常流程與出現的問題分離。
定義一個方法,用于計算圓(Circle)和長方形(Rectangular)的面積。由于計算的都是圖形的面積,但是圓和長方形的面積公式不同,及實作的具體内容不同,可以定義一個接口,在接口中定義一個沒有主體的方法,讓子類具體實作(當然,也可以将計算面積的功能視為基本功能,定義抽象類和抽象方法,讓子類複寫父類的方法,并定義自己的具體計算方式)。
由于我們編寫的程式是供使用者使用的,他們不知道輸入的内容具體是什麼,如輸入的數值是小于0的數,這時有可能出現問題。是以,要定義異常處理方式來避免問題的發生。
[align=center]-------[url]http://www.itheima.com[/url]java教育訓練、android教育訓練期待與您交流!------- [/align][/size]