異常(Exception)

Java學習筆記——異常(Exception)

異常的分類

img

Throwable類

Throwable:全部異常都是由Throwable繼承而來的,能夠經過繼承Throwable來實現新的異常,可是通常不推薦這樣作,下一層分爲了兩個分支:ErrorExceptionjava

Error類

Error類來用描述java運行時系統內部引發的錯誤和資源消耗錯誤,由於是java內部的錯誤,所以編寫的應用程序無能爲力。數組

Exception類

Exception:Exception類又能夠分爲IOExceptionRuntimeException,通常程序應該經過檢測的方式儘可能避免RuntimeException(也就是說出現這種異常就是編寫者本身的問題編寫者無須要捕獲這一類異常,相反,應該使用代碼if(obj == null)檢測避免出現NullPointExceptionide

RuntimeException類

RuntimeException:通常包括:學習

  • 錯誤的強制類型轉換:ClassCastException
  • 數組訪問越界:ArrayIndexOutOfBoundsException
  • 訪問null指針:NullPointerException

IOException類

常見的IOException類通常包括:‘this

文件末尾繼續讀取數據:EOFException線程

試圖打開一個不存在的文件:FileNotFoundException設計

根據給定的字符串查找class對象,可是該類不存在:ClassNotFoundException指針

...code

官方分類

Java通常把派生於Error類和RuntimeException類的異常稱之爲非檢查型異常,而IOException稱之爲檢查型異常orm

然而實際中,咱們可以進行處理的只有檢查型異常,由於檢查型異常在咱們我的的控制以內,非檢查型異常對於任何的代碼都有可能拋出,出現這些異常的時候咱們無法控制。

舉個例子:任何獲取對象引用的方法,都有可能獲取對象引用失敗而返回一個NullPointerException,這異常的出現是無法控制的,除非你給每個GetXX()方法都加上異常處理,可是這並不現實,所以不必處理非檢查型異常。

拋出異常

聲明檢查型異常

如何聲明檢查型異常

以下:

public FileInputStream(String name) throws FileNotFoundException

若要聲明多個檢查型異常,則須要用逗號分割

public Image loadImage(String name) throws FileNotFoundException, EOFException

注意這裏特別強調聲明檢查型異常,對於拋出非檢查型異常通常是不須要聲明的

何時須要聲明

兩種狀況:

  1. 調用一個拋出檢查型異常的方法的時候,傳遞異常的拋出,例如調用loadImage方法
  2. 方法自己須要拋出檢查型異常
// situation 1
public Image loadNewImage(String name) throws FileNotFoundException, EOFException{
	loadImage(name);
}

// situation 2
public Image importFile(String name) throws FileNotFoundException{
	file f = readfile(name);
	if(f == null){
		throw new FileNotFoundException();	// 拋出異常
	}
}

拋出異常

拋出異常的方法:

// method 1:
throw new EOFException(); // 拋出一個EOFException

// method 2:
var a = new EOFException();
throw a;					// 拋出一個EOFException

通常怎樣決定拋出異常呢?一般考慮的狀況是這樣:

  1. 找到一個合適的異常類
  2. 建立這一個異常類的對象
  3. 將對象拋出

一旦拋出異常以後,這個方法不會返回到調用者,也就是說無須要另外建議一個返回語句(return)

捕獲異常

捕獲異常

拋出檢查型異常以後,若是沒有對他進行捕獲,當前執行的線程都會終止,那麼如何捕獲異常?

try{
	// 先執行try裏面的語句
	// 一旦try裏面的有一條語句拋出ExceptionTypeX類型異常,則進入相應的catch語句,終止以後的try代碼塊的執行
}catch(ExceptionType1 e){
	// 在這裏處理異常
}catch(ExceptionType2 e){
	// 能夠捕獲多個異常
}catch(ExceptionType3 | ExceptionType4 e){
	// 若是拋出的兩個異常是不一樣的,可是他們的處理方法都同樣的話,還能夠這樣捕獲
	// 注意這種方式捕獲異常時,變量e被隱式聲明爲final,所以不能改變e的值
}
}finally{
	// 不管是否發生異常,最後都會運行此處的代碼,一般用於釋放資源
	// finally代碼塊能夠省略
	// 注意不要把控制流的語句放在finally(return,throw,break,continue),由於會發生意想不到的錯誤
	// 同時也不該該過度依賴finally,通常的設計原則是將finally應用在關閉資源或者釋放資源,如關閉IO流等
}

捕獲異常仍是傳遞異常

咱們能夠經過捕獲異常來處理方法拋出的異常,可是並不是每個異常咱們都知道怎麼去處理,那要如何解決?

咱們知道一個方法調用方法A,方法A會調用另一個可能拋出異常的方法B時,咱們能夠經過在方法A中聲明檢查型異常的方式,來將方法B中的異常傳遞給調用了方法A的那一個方法(說得更加直白一點就是A方法將B方法拋給A的異常再次拋出給A的調用者),讓它來解決這一個異常,所以對於上面的問題,咱們就能夠採用這種方式來解決,相似於下面的解決方式。

public A() throws Exception {
	B();
}
public B() throws Exception {
	... // 處理代碼
	if(...){
		throw new Exception();
	}
}

public fun(){
	try{
		A();
	}catch(Exception e){
	  // do something
	}
}

實際上對於應該捕獲異常仍是傳遞異常這一個問題,最好的答案是除非你知道怎麼解決,不然就應該什麼都不作,將異常傳遞給最終的調用者,讓最終調用者來處理這個問題是最好不過的。

不過這種解決方案有一個例外:這個例外體如今繼承特性上:

若是一個子類覆蓋了超類的一個方法,那麼子類要麼不拋出異常,要麼拋出的異常必須是超類異常的子類(也就是說子類須要拋出更加具體的異常),一樣,若是覆蓋的超類方法沒有拋出異常,那麼子類的覆蓋方法也不能拋出異常。

所以,若是覆蓋的超類方法沒有拋出異常,而子類的覆蓋方法又調用了其餘可能拋出異常的方法,這種時候就必須在覆蓋方法中捕獲全部的異常。

自定義異常類

一般咱們須要知足咱們我的的一個程序須要的時候就須要自定義異常類,異常類的定義能夠經過派生任何Exception類或者它的子類如IOException類來完成

public FileFormatException extends IOException
{
	public FileFormatException(){}
	public FileFormatException(String gride){
		super(gride);
	}
}
// 這樣就能夠完成本身的異常的定義了

異常鏈與異常再次包裝

異常嵌套

先看下面的代碼:

InputStream i = ...;
try{
 ...	// code 1
 	try{
 		// code 2
 	}catch(Exception e){
 	
 	}finally{
 		i.close();	
 	}
}catch(IOException e){

}

若finally中發生異常,則交由外層捕獲處理,若code 2位置發生異常,交由內層處理

再次拋出異常

不少時候咱們不知道須要具體拋出一個什麼異常,或者拋出去的異常可能帶有選擇性等狀況,這時候就須要再次拋出新的子類異常,相似於下面的狀況

try{

}catch(IOException e){
	throw new FileNotFoundException();
}

包裝技術

對於再次拋出異常,如何防止原父類異常中的信息丟失?

try{

}catch(IOException e){
	var a  = new FileNotFoundException();
	a.initCause(e);
	throw a;
}

捕獲異常時,使用

Throwable original = a.getcause();

就能夠獲取高層原始異常信息了。

包裝技術很是有用,能夠將多種異常包裝成一類異常拋出,同時保留高層原始異常的信息。

try-with-resource語句

該語句用於簡化try-catch-finally語句中的釋放工做

要使用try-with-resource語句,須要res實現AutoCloseable接口,該接口只有一個方法

void close() throws Exception
try(Resource res = ...){
	// work
}

使用try-with-resource,代碼段在運行結束以後,不管是否有異常拋出,都會調用res中實現的close()

通常狀況下,只要須要關閉資源,就要儘量使用try-with-resource

異常類相關方法

java.lang.Throwable

Throwable()										// 構造一個新的Throwable對象,但沒有詳細的描述信息
Throwable(String message)						// 構造一個新的Throwable對象,帶有詳細的描述信息
String getMessage()								// 獲取Throwable對象的詳細描述信息

// 一般用於包裝的構造方法
Throwable(Throwable cause)						// 用給定的cause(緣由)構造來構造Throwable對象
Throwable(String message, Throwable cause)		// 用給定的cause(緣由)構造和描述信息來構造Throwable對象
Throwable initCause(Throwable cause)			// 爲這個對象設置緣由,若是對象已有緣由則拋出異常,返回this
Throwable getCause()							// 獲取這個對象所設置的緣由,若是沒有返回null

java.lang.Exception

Exception(Throwable cause)
Exception(String message, Throwable cause)		// 用給定的cause(緣由)來構建Exception對象
相關文章
相關標籤/搜索