1. 程式人生 > 其它 >java面向物件-6(異常)

java面向物件-6(異常)

技術標籤:javaexception

java面向物件-6

異常定義和分類

異常機制是程式執行出現問題後,程式的處理機制。可理解為正常程式執行出現問題後的PlanB

程式錯誤分為三種:編譯異常、執行異常和邏輯錯誤。

(1)編譯異常是因為程式沒有遵循語法規則,編譯程式能夠自己發現並且提示我們異常的原因和位置

(2)執行時異常是因為程式在執行時,執行環境發現了不能執行的操作。

(3)邏輯錯誤是因為程式沒有按照預期的邏輯順序執行。異常也就是指程式執行時發生錯誤,而異常處理就是對這些錯誤進行處理和控制。

執行異常的父類是RuntimeException,RuntimeException的父類是Exception,Exception的父類是Throwable

異常的處理

try…catch

/*try...catch即為捕獲要發生的異常
若異常未發生,按照try程式碼塊執行,若異常發生了,則按照catch程式碼塊執行
邏輯類似於if*/
public static void main(String[] args){
	try{
		//會先執行try程式碼塊,在異常出現之前的程式碼可以執行到;
		System.out.println("進入try程式碼塊");
		int a=1/0;
		System.out.println("出現異常,本行程式碼無法被執行");
	}catch( ArithmeticException ae)
{ System.out.println("捕獲到異常,進入catch程式碼塊"); //列印全部的異常資訊,JVM處理異常時也是呼叫此方法 ae.printStackTrace(); //列印異常原因,但是不會有異常型別和問題程式碼定位 System.out.println(ae.getMessage()); } System.out.println("因為異常被捕獲,本行程式碼可以執行"); }

執行結果:

在這裡插入圖片描述

可以看到,程式順利結束(產生異常結束時,exit cot 1)

printStackTrace()方法列印格式錯亂的原因:當執行到產生異常的程式碼時,會新開一個執行緒去繼續執行程式碼,原執行緒列印錯誤資訊,執行緒列印資訊不具有原子性,可以多嘗試幾次,格式錯亂的結果會不一樣

public static void main(String[] args){
	try{
		System.out.println("進入try程式碼塊");
		int a=1/0;
		System.out.println("出現異常,本行程式碼無法被執行");
	}catch( ArithmeticException ae){
		System.out.println("捕獲到異常,進入catch程式碼塊");
		ae.printStackTrace();
		System.out.println(ae.getMessage());
	}finally{//上面部分還是一樣的
		//finally程式碼塊無論是否發生了異常都會執行
		System.out.println("進入finally程式碼塊");//本行語句一定會輸出
	}
	System.out.println("因為異常被捕獲,本行程式碼可以執行");
}
//當try...catch...finally被定義在方法中時
private static void method(){
	try{
		System.out.println(1);
		System.out.println(1/0);
	}catch (ArithmeticException ae){
		System.out.println(2);
		/*特別注意這裡,發生了異常,在catch程式碼塊中執行到了return,
		但是方法不會立刻結束,仍會執行finally程式碼塊,執行完畢後結束方法*/
		return;
	}finally {
		System.out.println(3);
	}
}
//呼叫本方法輸出結果為:1	2	3

//當方法有返回值的時候
private static int method(){
	int i=0;
	try{
		i++;
		i=1/0;
		i++;
	}catch (ArithmeticException ae){
		/*當執行到這裡時,會返回i+1=2,將值返回後,
		仍會執行finally,i值變為3,但是不會重複返回*/
		return ++i;
	}finally {
		i++;
	}
	return i;//本行程式碼不會被執行到
}
//呼叫本方法輸出結果為:2

private static int method(){
	int i=0;
	try{
		i++;
		i=1/0;
		i++;
	}catch (ArithmeticException ae){
		return ++i;
	}finally {
		i++;
		/*雖然catch程式碼塊返回了數值2,但是仍會執行finally程式碼塊
		而finally程式碼塊中也會返回一次,會覆蓋上次返回結果*/
		return i;
	}
}
//呼叫本方法輸出結果為:3
/*結論:
在try-catch-finally結構中,會先進入try程式碼塊執行,
如果沒有發生異常,就會執行try和finally程式碼塊的內容後結束;
如果發生了異常就會執行try中發生異常前的部分,catch和finally程式碼塊後結束;
當執行過程中,遇到return語句時,仍會繼續執行finally程式碼塊;
可理解為執行到return時先將結果返回,再去執行finally程式碼塊,除非finally
程式碼塊中也有return覆蓋原有結果,否則執行finally程式碼塊不影響返回的結果,
這是因為方法返回基本數值時並非返回該變數,而是返回數值本身,如果返回值是
引用資料型別,返回結果會保留方法最後一次操作的結果(結果類似遞迴)

例外情況:當執行到System.exit()時,程式會強制結束,finally將不再執行;
*/

throws

丟擲異常,throws的作用是將異常丟擲,交給呼叫者去處理

異常可以層層向上丟擲,由產生異常的方法拋給方法的呼叫者,方法呼叫者可以選擇try-catch解決異常,也可以繼續丟擲,直到拋給main方法

main方法中的異常最好使用try-catch解決掉,因為此時在throws丟擲會將異常拋給JVM處理,異常發生則會中斷程式

throws使用格式:

//可以同時丟擲多個異常,中間使用逗號隔開
//也可以丟擲一個大異常,同時cover多個異常
public static void method()throws FileNotFoundException,ArithmeticException{
	int i=1/0;
	FileInputStream fis=new FileInputStream("");
}

自定義異常

定義步驟:

1、建立一個類,類名命名為想要建立的異常的名字

2、繼承RuntimeException、Exception或者Throwable類,如果希望 編譯期報錯,則繼承Exception,希望執行期報錯,則繼承RuntimeException

3、定義構造方法,引數列表為異常提示資訊,使用super關鍵字呼叫父類構造方法,傳入異常提示資訊

自定義異常類建立過程(以RuntimeException子類為例):

public class AgeException extends RuntimeException{
    public AgeException(String message){
        super(message);//傳入異常提示資訊
    }
}

//在Exception和RuntimeException中也是層層呼叫父類構造方法建立異常的
public RuntimeException(String message) {
	super(message);
}
public Exception(String message) {
	super(message);
}

//在Throwable類中定義了異常資訊屬性
private String detailMessage;
public Throwable(String message) {
	fillInStackTrace();
	detailMessage = message;//最終異常資訊會傳遞到這裡,交由detailMessage屬性儲存
}
//當呼叫printStackTrace和getMessage時則會將detailMessage輸出和返回
public String getMessage() {
	return detailMessage;
}