java異常處理機制其最主要的幾個關鍵字:try、catch、finally、throw、throws,以及各種各樣的exception。本篇文章主要在基礎的使用方法上,介紹了如何更加合理的使用異常機制。
try-catch-finally
try-catch-finally塊的用法比較簡單,使用頻次也最高。try塊中包含可能出現異常的語句(當然這是人為決定的,try理論上可以包含任何代碼),catch塊負責捕獲可能出現的異常,finally負責執行必須執行的語句,這里的代碼不論是否發生了異常,都會被執行。
針對這部分,因為很基礎,所以就提幾點比較關鍵的建議:
1、當你在寫try-catch語句的時候,腦子里是知道自己要去針對哪種異常進行處理的,不要只是以防萬一,加了個catch(exception e),這是毫無意義的。并且,一個try塊中可能有多個異常,對于每一類異常,要分別寫一個catch進行捕獲。
2、針對可能出現異常的語句進行try-catch,大段代碼的try-catch會非常不利于維護代碼時定位異常可能發生的位置,對于肯定不會發生異常的穩定的代碼,不需要放在try塊中。
3、try-catch雖然在功能上,可以成為流程控制的工具,達到條件分支的效果。但相比于if-else語句,java的異常處理機制基于面向對象的思想,使用過程中需要更多的時間與空間的開銷,所以不要用異常機制去做基本的條件判斷,只有在程序會因為異常而中斷時進行捕獲和處理。
4、finally塊中永遠不要寫return語句,因為finally塊中總是最后執行,他會改變預期在try和catch塊中的返回值(舉個例子,你在catch中捕獲了一個異常并拋出e,又在finally語句中return true,這樣你拋出的異常就"消失"了,因為當前函數的執行結果已經從拋出異常 轉變成 return true)。另外,在使用資源對象與流對象時,finally塊必須對資源對象、流對象進行關閉。
java異常體系結構
java異常體系的基類是throwable,它主要有兩個子類:error 和 exception。其結構如下圖:
上圖中,error是指程序無法處理的錯誤,多指系統內部比較嚴重的錯誤。大多數這類錯誤與開發人員無關,我們關注的主要是exception。
exception主要分為兩塊:運行時異常和非運行時異常。runtimeexception及其子類都稱為運行時異常;除此之外, 所有exception的子類異常都是非運行時異常。
運行時異常多指程序邏輯上出現問題(也就是我們自己寫代碼邏輯出了問題),常見的錯誤包括 classcastexception:類型轉換異常、nullpointerexception:空指針異常、indexoutofboundsexception:越界異常...這些異常都可以通過程序邏輯處理來避免(比如加一個判斷語句判斷是否越界、是否屬于某類型、是否為null),所以編譯器把這些工作交給了程序員來把控,在編譯期即使手動拋出了一個運行時異常不去捕獲,編譯器也會通過。因而這類異常也叫做"未檢查異常"(uncheck)。同樣屬于未檢查異常的還有所有的error。即上圖中,所有藍色框表示未檢查異常,橙色框表示"檢查異常"(check)。對于檢查異常,在可能發生異常的位置需要用try-catch塊去捕獲并處理,如果不處理它,就會一直向上層調用拋出,直到被處理為止。
throw 與 throws
throws關鍵字主要在方法簽名中使用,用于聲明該方法可能拋出的異常。throws 可以理解成是一種通知行為,沒有實際的拋出異常的動作,而僅僅是告訴調用他的上層函數,這里可能會拋出這個異常;
throw用于在函數體內語句中,表示拋出一個實際的異常的實際動作,如果在函數內沒有捕獲并處理,那么將會一直向上拋出這個異常直到被main()/thread.run()拋出。
當一個函數throws聲明函數可能拋出一個非運行時異常(檢查異常)時,那么即使這個函數內部不顯示使用throw,調用它的上層函數也必須包含處理這個異常的代碼。舉個例子:
public class main {
public static void main(string[] args){
exceptiontest();
}
static int exceptiontest() throws ioexception {
return 0;
}
}
上述代碼中調用的exceptiontest函數聲明拋出一個ioexception屬于檢查異常,哪怕exceptiontest函數中不可能拋出這個異常,調用它的函數也必須對此異常做出捕獲處理。現在main函數中沒有相關的處理邏輯,所以會編譯錯誤,如下圖:
而對運行時異常,就是另一種情況了:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class main { public static void main(string[] args){ int i = dividetest( 0 ); system.out.println(i); } static int dividetest( int b) throws arithmeticexception { int i = 5 /b; return i; } } |
同樣在main函數沒有處理異常的邏輯,這次聲明拋出的異常是arithmeicexception,他屬于運行時異常(runtimeexception),所以編譯器對聲明的拋出置之不理:
雖然編譯期通過,但在運行時程序仍然會自動拋出運行時異常,并一直向上拋出到main函數。而main()中沒有對該異常的捕獲處理,所以主線程終止。
結論:我目前的理解是,throws一個運行時異常是沒有任何實際意義的,除非你為了遵循某個統一的規范而這樣做。throws 存在的意義主要是將可能的非運行時異常交給編譯器把關,讓編譯器監督開發人員對這些異常進行捕獲處理。
另外,當你需要自定義一個異常時,如果需要在編譯期檢查,并在上層統一處理,那么直接繼承exception成為一個檢查異常;如果不需要編譯期檢查,拋出異常表示程序異常需要直接中斷,那么繼承runtimeexception成為一個運行時異常即可。
希望本篇文章可以對各位朋友有所幫助!
原文鏈接:http://www.cnblogs.com/jzb-blog/p/6693434.html