天天看點

黑馬程式員----面向對象---異常

[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]