異常

異常的概述

1.1什麼是異常?

異常:程序在運行過程中發生由於外部問題導致的程序異常事件,發生的異常會中斷程序的運行。(在Java等面向對象的編程語言中)異常本身是一個對象,產生異常就是產生了一個異常對象。注意在java中異常不是錯誤,在下文的異常的分類中有解釋。

1.2 如何處理異常?

1.2.1 傳統的異常處理

假如現在要求在控制檯中,輸入被除數和除數,求商。

傳統做法是這樣的:

public static void main(String[] args) {
	System.out.println("請輸入一個被除數:");
	Scanner sc = new Scanner(System.in);
		int num1 = sc.nextInt;
		System.out.println("請輸入一個除數:");
		int num2 = sc.nextInt;
			if(num2== 0) {
				System.out.println("除數不能爲0!");
			}else {
				int r = num1 / num2;
				System.out.println("r = " + r);
			}
}

從上面這個例子可以可以看出,這麼簡單的業務需求,代碼也要寫得那麼長,因爲要考慮的問題有很多,這樣寫代碼會覺得很累,而且出現了異常,程序會中斷,不會執行後面的代碼。因此,Java編程語言使用異常處理機制爲程序提供異常處理的能力。

1.2.2 java的異常處理

在Java中,異常處理的過程:
這種處理過程就像你上班遇到公路施工,你做出了處理——繞路行走,避開施工路段,讓你按時到達公司!

2.異常的分類

在 Java 中,所有的異常都有一個共同的祖先 Throwable(可拋出)。Throwable 指定代碼中可用異常傳播機制通過 Java 應用程序傳輸的任何問題的共性。
Throwable: 有兩個重要的子類:Exception(異常)和 Error(錯誤),二者都是 Java 異常處理的重要子類,各自都包含大量子類。

***Error(錯誤)***:是程序無法處理的錯誤,表示運行應用程序中較嚴重問題。大多數錯誤與代碼編寫者執行的操作無關,而表示代碼運行時 JVM(Java 虛擬機)出現的問題。例如,Java虛擬機運行錯誤(Virtual MachineError),當 JVM 不再有繼續執行操作所需的內存資源時,將出現 OutOfMemoryError。這些異常發生時,Java虛擬機(JVM)一般會選擇線程終止。

這些錯誤表示故障發生於虛擬機自身、或者發生在虛擬機試圖執行應用時,如Java虛擬機運行錯誤(Virtual MachineError)、類定義錯誤(NoClassDefFoundError)等。這些錯誤是不可查的,因爲它們在應用程序的控制和處理能力之 外,而且絕大多數是程序運行時不允許出現的狀況。對於設計合理的應用程序來說,即使確實發生了錯誤,本質上也不應該試圖去處理它所引起的異常狀況。在 Java中,錯誤通過Error的子類描述。

***Exception(異常)***:是程序本身可以處理的異常。Exception 類有一個重要的子類 RuntimeException。RuntimeException 類及其子類表示“JVM 常用操作”引發的錯誤。例如,若試圖使用空值對象引用、除數爲零或數組越界,則分別引發運行時異常(NullPointerException、ArithmeticException)和 ArrayIndexOutOfBoundException。注意:異常和錯誤的區別:異常能被程序本身可以處理,錯誤是無法處理。通常,Java的異常(包括Exception和Error)分爲可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。

受查異常(編譯器要求必須處置的異常):正確的程序在運行中,很容易出現的、情理可容的異常狀況。受查異常雖然是異常狀況,但在一定程度上它的發生是可以預計的,而且一旦發生這種異常狀況,就必須採取某種方式進行處理。

除了RuntimeException及其子類以外,其他的Exception類及其子類都屬於受查異常。這種異常的特點是Java編譯器會檢查它,也就是說,當程序中可能出現這類異常,要麼用try-catch語句捕獲它,要麼用throws子句聲明拋出它,否則編譯不會通過。

運行時異常(RuntimeException):本身和其子類均爲運行時異常,可處理可不處理。

不可查異常(編譯器不要求強制處置的異常):包括運行時異常(RuntimeException與其子類)和錯誤(Error)。

Exception 這種異常分兩大類運行時異常和非運行時異常(編譯異常)。程序中應當儘可能去處理這些異常。

運行時異常:都是RuntimeException類及其子類異常,如NullPointerException(空指針異常)、IndexOutOfBoundsException(下標越界異常)等,這些異常是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。這些異常一般是由程序邏輯錯誤引起的,程序應該從邏輯角度儘可能避免這類異常的發生。運行時異常的特點是Java編譯器不會檢查它,也就是說,當程序中可能出現這類異常,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯通過。

非運行時異常 (編譯異常):是RuntimeException以外的異常,類型上都屬於Exception類及其子類。從程序語法角度講是必須進行處理的異常,如果不處理,程序就不能編譯通過。如IOException、SQLException等以及用戶自定義的Exception異常,一般情況下不自定義檢查異常。

3.異常處理機制

通過上面對異常的解釋,現在應該對異常有一定的瞭解。下面來說明在java中是如何處理異常的。

•在java中用對象來表示異常的。

•java是通過
try{}-catch(){}、
try{}-catch(){}-finally{}、
try{}-catch(){}-catch(){}…finally{}、
try{} - finally{}語句來處理異常的。

3.1 try-catch

3.1.1 try-catch的使用

try{} 代碼塊用於執行可能存在異常的代碼,catch(異常類型 異常對象的名稱){}代碼塊用於捕獲並處理異常。

try{

//有可能出現異常的代碼段1

//有可能出現異常的代碼段2

}catch(異常類型 e){

//處理異常的代碼段3

}

//代碼段4

處理兩數相除問題的demo:

public static void main(String[] args) {

	Scanner sc = new Scanner(System.in);
	
	try{
	
		System.out.println("請輸入一個被除數:");
	
		int num1=sc.nextInt;
	
		System.out.println("請輸入一個除數:");
	
		int num2=sc.nextInt;
	
		int result=num1/num2;
	
	}catch(Exception e){
	
		System.out.println("除數不能爲0");//處理異常,通俗的說就是自己劃定規則
	
	}
	System.out.println(result);

	System.out.println("程序運行結束");

}

3.1.2 try-catch的執行順序

第一種:沒有遇到異常,即正常執行

第二種:匹配到異常

在try{}中的代碼遇到異常時,會與catch中括號裏的異常進行比對,如果遇到的異常時屬於catch的異常就會執行catch塊中的代碼,讓後執行try-catch塊後面的代碼

第三種:匹配不到異常

3.2try-catch-finally

try{} 代碼塊用於執行可能存在異常的代碼,catch{}代碼塊用於捕獲並處理異常。

finally{} 代碼塊用於回收資源(關閉文件、關閉數據庫、關閉管道)的代碼。finally代碼塊不管是否出現異常,都必須執行( finally塊唯一不執行的情況System.exit(0) jvm正常退出。)

3.1.1 try-catch-finally的執行順序

第一種:catch塊沒有return語句

(1)沒有遇到異常:

try塊內的代碼——>finally塊內的代碼——>finally塊後的代碼

(2)遇到異常並匹配到異常:

try塊內的代碼——>catch塊內的代碼——>finally塊內的代碼——>finally塊後的代碼

public class Test01 {

	public static void main(String[] args) {
	
		try {
		
			int a=1/0;
		
			System.out.println("try");
		
		} catch (Exception e) {
		
			System.out.println("catch");
		
		}finally {
		
			System.out.println("finally");
		
		}
		
		System.out.println("程序正常運行結束");
	
	}

}

結果:

1 catch

2 finally

3 程序正常運行結束

(3)遇到異常卻沒有匹配到異常:

try塊內的代碼——>finally塊內的代碼——>程序中斷運行

public static void main(String[] args) {

	try {
	
		int a=1/0;//會拋出ArithmeticException
		
		System.out.println("try");
	
	} catch (NullPointerException e) {
	
		System.out.println("catch");
	
	}finally {
	
		System.out.println("finally");
	
	}
	
		System.out.println("程序正常運行結束");

}

結果:

1 Exception in thread “main” finally

2 java.lang.ArithmeticException: / by zero

3 at Test1.Test01.main(Test01.java:8)

第二種:catch塊有return語句

(1)沒有異常

try塊內的代碼——>finally塊內的代碼——>try塊內的return語句

public class Test01 {
	public static int test {	
		try {		
			int a=2*2;		
			System.out.println("try");		
			return a;		
		} catch (Exception e) {
			System.out.println("catch");		
			return 0;		
		}finally {	
			System.out.println("finally");
	}
	
	}
	
	public static void main(String[] args) {
	
	System.out.println(test);
	
	System.out.println("程序正常運行結束");
	
	}

}

結果:

1 try

2 finally

3 4

4 程序正常運行結束

(2)遇到異常並匹配到異常:

執行順序如圖:

public class Test01 {

	public static int test() {
	
		try {
		
			int a=2/0;
		
		System.out.println("try");
		
			return a;
			
		} catch (Exception e) {
		
			System.out.println("catch");
		
			return 0;
		
		}finally {
		
			System.out.println("finally");
		
	}
	
	}
	
	public static void main(String[] args) {
	Test01 test = new Test01();
		
	System.out.println(test.test());
	
	System.out.println("程序正常運行結束");
	
	}

}

結果:

1 catch

2 finally

3 0

4 程序正常運行結束

(3)遇到異常卻沒有匹配到異常:

try塊內的代碼——>finally塊內的代碼——>程序中斷運行

public class Test01 {

	public static int test() {
	
		try {
		
			int a=2/0;
		
			System.out.println("try");
		
			return a;
		
		} catch (NullPointerException e) {
		
			System.out.println("catch");
		
			return 0;
		
		}finally {
		
			System.out.println("finally");
		
		}
		
	}
		
		public static void main(String[] args) {
		
			Test01 test = new Test01();
		
			System.out.println(test.test());
		
			System.out.println("程序正常運行結束");
	
		}

}

結果:

finally

Exception in thread “main” java.lang.ArithmeticException: / by zero

at Test1.Test01.test(Test01.java:8)

at Test1.Test01.main(Test01.java:19)

  1. 聲明異常

4.1 throws

當開發者在定義方法時,事先知道方法在調用時會出現異常,但不知道該如何處理,此時可以在該方法上聲明異常。表示該方法在調用過程中會出現異常,請調用者自行處理。

在java中使用throws 聲明異常。一個方法可以聲明多個異常,用,號分割,寫法如下:

1 public void test2throws IOException,RuntimeException{

2 //有異常出得代碼,在此處沒有處理

3 }

4.2 聲明異常與方法重載的關係

聲明異常和方法重載沒有任何關係。

4.3 聲明異常與方法重寫的關係

•如果父類方法聲明瞭異常(受查時或運行時),子類方法可以完全遵循父類異常,也可以不聲明異常。

•如果父類方法沒有聲明異常,子類也不聲明異常

•如果父類聲明瞭運行時異常,子類可以完全遵循父類異常,也可以不聲明異常。

5.拋出異常

當系統異常滿足不了開發需要時,開發者可以自行根據需要自行拋出異常。

throw 用於手動拋出異常。

如果一直都沒有處理(即沒有用try-catch等語句)異常會把異常拋給調用者,一直拋到main函數處,如果在main函數中也沒有處理繼續在main函數後拋出異常,這時候會拋給jvm處理。如下栗子:

public class Test01 {

public static void test1throws IOException,RuntimeException{

//有異常拋出得代碼,在此處沒有處理,例如:throw new Exception(“異常信息”);

}

public static void test2 throws IOException,RuntimeException{

test1;//調用有拋出異常的方法,在此沒有處理

}

public static void main(String[] args)throws IOException,RuntimeException {

test2;//main調用有拋出異常的方法,在此沒有處理

}

}

注意:

開發者根據自身需要可以選擇拋出檢查時異常和運行時異常

  1. 自定義異常

當JDK 中的異常類型不能滿足程序的需要時,可以自定義異常類。

自定義異常步驟:

•[1] 確定異常類型.繼承Excepion 或者RuntimeException

•[2] 編寫自定義異常類,並實現構造方法

•[3] 在方法需要的地方手動聲明並拋出異常。

public class myException extends Exception {

	public myException {
	
		super;
	
	}
	
	public myException(String message) {
	
		super(message);
	
	}
	
	//自定義異常中的方法,以符合自己的需求
	
	public void showInfo {
	
		System.out.println(super.getMessage+"@Line:");
	
	}

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