異常(一)

1、什麼是異常?

異常,就是指程序在運行時出現不正常的情況。

        異常也是某種意義上的錯誤,就是問題,雖然編譯通過了,但會導致運行失敗。

(1)異常的由來:

          問題也是現實中的一個具體的事物,也可以通過Java類的形式進行描述,並封裝成對象。

          其實就是Java對不正常情況進行描述後的對象體現。

          問題封裝成對象。

(2)對於問題的劃分,分爲兩種:

          一種是嚴重的問題,一種是非嚴重的問題。

          對於嚴重的,Java通過Error類進行描述。

          對於Error,一般不編寫針對性的代碼對其進行處理。

          對於不嚴重的,Java通過Exception類進行描述。

          對於Exception,可以使用針對性的處理方式進行處理。

          無論Error還是Exception,都具有一些共性的內容。

          比如:不正常的信息,引發原因等。

          函數有異常發生時,函數就停止,所以兩個異常不能同時處理。

2、異常的處理

Java提供了特有的語句對異常進行處理。

try

{

    需要被檢測的代碼;

}

catch(異常類 變量)

{

    處理異常的代碼;

}

finally

{

一定會執行的語句;

}

代碼示例:

class ExceptionDemo {
	public static void main(String[] args){
		Demo d = new Demo();
		
		try{
			int f = d.div(5,0);     //函數有異常發生,函數就停止,所以兩個異常不能同時處理。
			System.out.println(f);
		}
		catch(Exception e){
		        System.out.println(e.toString());  //捕獲異常,並處理
			System.out.println("除零啦");
		}
		
		System.out.println("over");
	}
}
class Demo {
	int div(int a,int b) throws Exception {
		return a/b;                 //會出現異常,除數不爲零
	}
}


出現異常不進行處理時,默認打印異常信息:



對異常用try-catch進行處理後:



(1)對捕獲到的異常進行常見方法操作:

//e爲異常對象

e.toString();        //打印異常的簡短描述

String getMessage();    //獲取異常的信息

e.printStackTrace();      //JVM默認的異常處理機制,就是在調用printStackTrace()方法打印異常的堆棧跟蹤信息。

(2)在函數上聲明異常,即 throws Exception

便於提高安全性,要捕獲進行處理,不處理編譯失敗。

函數後使用 throws 關鍵字聲明此函數可能會出現問題。

3、對多異常的處理

(1)聲明異常時,建議聲明爲更具體的異常,這樣處理的可以更具體。

例如,上面除數爲0的異常爲算數異常,可以聲明爲ArithmeticException,更爲具體。

(2)對方聲明幾個異常,就對應幾個catch塊,不要定義多餘的catch塊。

如果多個catch塊中的異常出現繼承關係,父類異常catch塊放在最下面.(ArithmeticException就繼承了Exception)

否則,只執行父類異常的catch塊。

(3)異常中的多態性,父類異常也是多態性的體現,拋出的異常對象可以是父類引用。

(4)建議在進行catch處理時,catch中一定要定義具體處理方式,不要簡單定義一句輸出語句 e.printStackTrace(),而是輸出爲一個異常日誌文件。

多異常處理的Demo:

class ExceptionDemo {
	public static void main(String[] args){
		Demo d = new Demo();
		
		try{
			int f = d.div(5,0);     //函數有異常發生,函數就停止,所以兩個異常不能同時處理。
			System.out.println(f);
		}
		catch(ArithmeticException e){
		    System.out.println(e.toString());//捕獲算數異常,並處理
			System.out.println("除零啦");
		}
		
 		catch(ArrayIndexOutOfBoundsException c){  //捕獲腳標越界異常,並處理
			System.out.println(c.toString());    
			System.out.println("數組腳標越界啦");
		}
		
		catch(Exception e) {    //父類異常放在最下面,否則只執行父類異常
			System.out.println("haha:"+e.toString());
		} 
		
		System.out.println("over");
	}
}
class Demo {
	int div(int a,int b) throws ArithmeticException,ArrayIndexOutOfBoundsException {
 		int[] arr = new int[a];
		System.out.println(arr[4]);  //會出現腳標越界異常 
		return a/b;                 //會出現算數異常,除數不爲零
	}
}

結果爲除數爲0異常:


int f = d.div(5,0);

改爲

int f = d.div(4,1);

就會出現數組腳標越界異常:


3、自定義異常

因爲項目中會出現特有的問題,而這些問題並未被Java所描述並封裝對象。

所以對於這些特有的問題,可以按照Java的對問題封裝的思想,將特有的問題,進行自定義的異常封裝。

那麼就需要對這個問題進行自定義的描述。

(1)當在函數內部出現了 throw 拋出異常對象,那麼就必須給出對應的異常處理:

                要麼在內部 try-catch 處理;

                要麼在函數上聲明異常,讓調用者處理,

                 一般情況下,函數內出現異常,函數上需要聲明。

(2)發現打印的結果中只有異常的名稱,卻沒有異常的信息,因爲自定義的異常並未定義信息。

(3)如何定義異常信息呢?

                因爲父類中已經把異常信息的操作都完成了,

                所以子類只要在構造時,通過 super() 語句,將異常信息傳遞給父類,

                那麼就可以直接通過 getMessage() 方法獲取自定義的異常。

(4)自定義異常:

                自定義異常類必須繼承 Exception。

           繼承Exception 的原因:

                 異常體系有個特點:因爲異常類和異常對象都被拋出;

                 他們都具備可拋性,這個可拋型是 Throwable 這個體系中獨有的特點;

                 Throwable 是 Exception 和 Error 的父類,

                 只有這個體系中的類和對象纔可以被 throws 和 throw 操作。

(5)throws throw 的區別

             a)  throws 使用在函數上(大括號和小括號之間)。throw 使用在函數內。

             b)  throws 後面跟的是異常類,可以跟多個(多異常),用逗號隔開。

                   throw 後面跟的是異常對象(new關鍵字)。

             c)  一般情況下,函數內拋出異常,則該函數上必須拋出異常類。

                   RuntimeException 是特例。

自定義異常的Demo:

// 需求:在本程序中,對於除數是-1,也視爲是錯誤的是無法進行運算的,即自定義的異常。
class ZiDingYiException {
	public static void main(String[] args){
		Demo d = new Demo();
		
		try {
			int f = d.div(5,-1);     //函數有異常發生,函數就停止,所以兩個異常不能同時處理。
			System.out.println(f);
		}
		
		catch(ArithmeticException e){
			System.out.println(e.getMessage());
			System.out.println("除零啦");
		}
		
		catch(FuShuException e){
			System.out.println(e.getMessage());
			System.out.println("除數出現負數了");
		}
		
		System.out.println("over");
	}
}
class Demo {
	int div(int a,int b) throws ArithmeticException,FuShuException {  //會出現除數爲0異常和負數異常
		if(b<0){
			throw new FuShuException("出現了除數是負數的情況:/by fushu"); //手動通過throw關鍵字拋出異常對象,括號內爲定義的異常信息
		}
		return a/b;                 
	}
}
class FuShuException extends Exception{  //自定義的異常類中,需通過構造函數傳遞異常信息 
	private String msg;
	FuShuException(String msg){     //利用構造函數傳遞異常信息
		this.msg = msg;
	}
	public String getMessage(){    //重寫getMessage;給異常定義信息
		return msg;
	} 
}
/* 	因爲父類中已經把異常信息的操作都完成了。
  所以子類只要在構造時,將異常信息傳遞給父類通過super()語句。
  那麼就可以直接通過getMessage()方法獲取自定義的異常。 */
/* 	
	即 FuShuException() 函數中的三個語句,可以替換爲:
	
	FuShuException(String msg){
		super(msg);    
	}
	即 FuShuException類如下:
*/	

class FuShuException extends Exception{ 
	FuShuException(String msg){        //利用構造函數傳遞異常信息
		super(msg);                    //通過 super()語句,將異常信息傳遞給父類
	}
}

運行結果:


4、RuntimeException

(1)Exception中有一個特殊的子類異常,即 RuntimeException;

          如果在函數內拋出該異常,函數上可以不用聲明,編譯一樣通過;

          如果在函數上聲明瞭該異常,調用者可以不用進行處理,編譯一樣通過;

          之所以不用在函數上聲明,是因爲不需要讓調用者處理。當該異常發生,希望程序停止。

          因爲在運行時,出現了無法繼續運算的情況,希望停止程序後,對代碼進行修正

(2)自定義異常時:

          如果該異常發生,無法再繼續進行運算時,就讓自定義的異常繼承 RuntimeException 。

(3)對於異常分爲兩種:

           a)  編譯時被檢測的異常,Exception;

           b)  編譯時不被檢測的異常(運行時異常,RuntimeException及其子類)

                運行時異常,函數內拋出異常對象,函數上不用聲明異常,也不用在調用時處理異常。

RuntimeException的Demo:

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

		int f = d.div(5,0);
		System.out.println(f);

		System.out.println("over");
	}
}
class Demo {
	int div(int a,int b){    //throws ArithmeticException,因爲ArithmeticException是RuntimeException的子類
		if(b==0){
			throw new ArithmeticException(); //手動通過throw關鍵字拋出異常對象。
		}
		return a/b;        //會出現算數異常,除數不爲零
	}
}




發佈了39 篇原創文章 · 獲贊 7 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章