本文將向讀者介紹如何編寫正確的異常處理程序扛稽,并將展示當(dāng)方法出問題的時候柴灯,如何產(chǎn)生自定義異常物延。如有不對歡迎拍磚宣旱,謝謝。
文章出處
文章出自:安卓進(jìn)階學(xué)習(xí)指南
主要貢獻(xiàn)者:
justdoitJX
YangZhe
Milo
問題
- 什么是異常叛薯,異常的分類有哪些浑吟?
- RuntimeException和CheckedException的區(qū)別、error和exception的區(qū)別?
- 常見RuntimeException(運(yùn)行時異常)和CheckedException(檢查型異常)有哪些耗溜?
- 異常的機(jī)制(異常處理的流程)买置?
- 異常的使用方法(如何拋出異常,如何捕獲異常强霎,再次拋出異常)?
- throws,throw,try,catch,finally分別代表什么意義忿项?
- 什么是“異常鏈”?
- 怎么自定義異常?
- Java異常類有哪些的重要方法?
什么是異常
異常是發(fā)生在程序執(zhí)行過程中阻礙程序正常執(zhí)行的錯誤事件轩触;比如打開的文件不存在寞酿、網(wǎng)絡(luò)連接中斷、操作數(shù)組越界等都會導(dǎo)致出現(xiàn)異常脱柱。
異常的分類
異常的基類為Throwable伐弹,Error和Exception繼承Throwable。
Error(錯誤):是程序無法處理的錯誤榨为。這些錯誤表示故障發(fā)生于虛擬機(jī)自身惨好、或者發(fā)生在虛擬機(jī)試圖執(zhí)行應(yīng)用時,一般不需要程序處理随闺。
Exception:這種異常分兩大類RuntimeException(運(yùn)行時異常)和CheckedException(編譯時異常);
常見的RuntimeException有:
ArrayIndexOutOfBoundsException(數(shù)組索引越界異常)
NullPointerException(空指針異常)
ClassNotFoundException(找不到類異常)
IllegalArgumentException(非法參數(shù)異常)
SecurityException(安全性異常)
常見的CheckedException有:
NoSuchMethodException(方法未找到拋出的異常)
ClassCastException(類型轉(zhuǎn)換異常類)
NumberFormatException(字符串轉(zhuǎn)換為數(shù)字拋出的異常)
IOException(操作輸入流和輸出流時可能出現(xiàn)的異常)
Java 異常關(guān)鍵字:try日川、catch 、finally 矩乐、throw 龄句、throws
public Test() {
try {
int i = 10 / 0;
System.out.println("i=" + i);
} catch (ArithmeticException e) {
//捕獲 ArithmeticException
} catch (Exception e) {
//捕獲 Exception
throw e;
} finally {
//do something
}
}
public void test1() throws Exception {
//do something
}
1)異常處理機(jī)制
我們都知道除數(shù)不能為0,否則程序就會報錯散罕。像Java中其他對象的創(chuàng)建一樣分歇,使用new在堆上創(chuàng)建異常對象。然后終止當(dāng)前的執(zhí)行路徑欧漱,并且從當(dāng)前環(huán)境中彈出異常對象的引用职抡。此時,異常機(jī)制接管程序误甚,并開始尋找一個恰當(dāng)?shù)牡胤嚼^續(xù)執(zhí)行程序繁调。這個恰當(dāng)?shù)牡胤骄褪钱惓L幚沓绦颍娜蝿?wù)是將程序從錯誤狀態(tài)中恢復(fù)靶草,以使程序能要么換一種方式運(yùn)行,要么繼續(xù)下去岳遥。
2)拋出異常的方式
使用throw拋出異常:throw總是出現(xiàn)在函數(shù)體中奕翔,用來拋出一個Throwable類型的異常。程序會在throw語句后立即終止浩蓉,它后面的語句執(zhí)行不到派继,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊。例如拋出一個IOException類的異常對象:
throw new IOException
;throws拋出異常:如果一個方法可能會出現(xiàn)異常捻艳,但沒有能力處理這種異常驾窟,可以在方法聲明處用throws子句來聲明拋出異常。throws語句用在方法定義時聲明該方法要拋出的異常類型认轨,如果拋出的是Exception異常類型绅络,則該方法被聲明為拋出所有的異常。多個異常可使用逗號分割恩急。throws語句的語法格式為:
methodname throws Exception1,Exception2,..,ExceptionN {}
杉畜。
當(dāng)方法拋出異常列表的異常時,方法將不對這些類型及其子類類型的異常作處理衷恭,而拋向調(diào)用該方法的方法去處理此叠。
3)重新拋出異常
有時希望把剛捕獲的異常重新拋出,尤其是在使用Exception捕獲所有異常的時候随珠。既然已經(jīng)得到了對當(dāng)前異常的引用灭袁,可以直接把它重新拋出:
catch(Exception e){
System.out,println("An exception was thrown");
throw e;
}
重拋異常會把異常拋給上一級環(huán)境中的異常處理程序,同一個try塊的后續(xù)catch子句將被忽略窗看。
注意:
如果是Error茸歧、RuntimeException或它們的子類,那么不可使用throws關(guān)鍵字來聲明要拋出的異常烤芦,雖然編譯可以通過举娩,但是在運(yùn)行時會被系統(tǒng)拋出。
如果一個方法出現(xiàn)編譯時異常构罗,要么用try-catch語句捕獲铜涉,要么用throws子句聲明將它拋出,否則會導(dǎo)致編譯錯誤遂唧。
僅當(dāng)拋出了異常芙代,該方法的調(diào)用者才必須處理或者重新拋出該異常。
調(diào)用方法必須遵循任何可查異常的處理和聲明規(guī)則盖彭。若覆蓋一個方法纹烹,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類召边。
4)捕獲異常
在Java中铺呵,異常通過try-catch語句捕獲。其一般語法形式為:
try {
// 可能會發(fā)生異常的程序代碼
} catch (Type1 id1){
// 捕獲并處置try拋出的異常類型Type1
}
catch (Type2 id2){
//捕獲并處置try拋出的異常類型Type2
}
異常處理程序必須緊跟在try塊之后隧熙。當(dāng)異常被拋出時片挂,異常處理機(jī)制將負(fù)責(zé)搜尋參數(shù)與異常類型想匹配的第一個處理程序。然后進(jìn)入catch子句執(zhí)行贞盯,此時認(rèn)為異常的得到了處理音念。一旦catch子句結(jié)束,則處理程序的查找過程結(jié)束躏敢。只有匹配的catch子句才能得到執(zhí)行闷愤。
可以寫一個異常處理程序來捕獲所有類型的異常。
catch(Exception e){
System.out.println("Caught an exception");
}
這將捕獲所有異常件余,所以最好把它放在程序列表的末尾讥脐,以防它搶在其他處理程序之前先把異常捕獲了遭居。
因?yàn)镋xception是與編程有關(guān)的所有異常類的基類,所以他不會含有太多具體的信息攘烛,不過可以調(diào)用它從其基類Throwable繼承的方法:
String getMessage()
String getLocalizedMessage()
用來獲取詳細(xì)信息魏滚,或用本地語言表示的詳細(xì)信息。
String toString()
返回對Throwable的簡單描述坟漱,要是有詳細(xì)信息的話鼠次,也會把它包含在內(nèi)。
void printStackTrace()
void printStackTrace(PrintStream)
void printStackTrace(java.io.PrintWriter)
打印Throwable和Throwable的調(diào)用棧軌跡芋齿。其中第一個版本輸出到標(biāo)準(zhǔn)錯誤腥寇,后兩個版本允許選擇輸出的流。
Throwable fillInStackTrace()
用于在Throwable對象的內(nèi)部記錄棧幀的當(dāng)前狀態(tài)觅捆。這在程序重新拋出錯誤或異常時很有用赦役。
此外,也可以使用Throwable從其基類Object繼承的方法栅炒。
5)異常鏈
常常會想要在捕獲一個異常后拋出另一個異常掂摔,并且希望把原始異常的信息保存下來,這被稱為異常鏈∮蓿現(xiàn)在所有Throwable的子類在構(gòu)造器中都可以接受一個cause(因由)對象作為參數(shù)乙漓。這個cause就用來表示原始異常,這樣通過把原始異常傳遞給新的異常释移,使得即使當(dāng)前位置創(chuàng)建并拋出了新的異常叭披,也能通過這個異常鏈追蹤到異常最初發(fā)生的位置。
6)finally
無論是否捕獲或處理異常玩讳,finally塊里的語句都會被執(zhí)行涩蜘,甚至在異常沒有被當(dāng)前的異常處理程序捕獲的情況下,異常處理機(jī)制也會跳到更高一層的異常處理程序之前熏纯,執(zhí)行finally子句同诫,當(dāng)涉及break及continue語句的時候,finally子句也會得到執(zhí)行樟澜。當(dāng)要把除內(nèi)存之外的資源恢復(fù)到它們的初始狀態(tài)時误窖,就要用到finally子句,如已經(jīng)打開的文件或網(wǎng)絡(luò)連接往扔,在屏幕上畫的圖形,甚至可以是外部世界的某個開關(guān)熊户。
當(dāng)在try塊或catch塊中遇到return語句時萍膛,finally語句塊將在方法返回之前被執(zhí)行。在以下4種特殊情況下嚷堡,finally塊不會被執(zhí)行:
- 在finally語句塊中發(fā)生了異常蝗罗。
- 在前面的代碼中用了System.exit()退出程序艇棕。
- 程序所在的線程死亡。
- 關(guān)閉CPU串塑。
如何自定義異常
public class MyException extends Exception{
public MyException() {
}
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
public MyException(Throwable cause) {
super(cause);
}
}
public void test2() throws MyException {
//do something
throw new MyException("");
}
public void test3() {
//do something
try {
throw new MyException("");
} catch (MyException e) {
e.printStackTrace();
}
}
自定義異常通常是定義一個繼承自Exception類的子類沼琉。一般情況下我們都會直接繼承自Exception類,而不會繼承某個運(yùn)行時的異常類桩匪。在程序中使用自定義異常類打瘪,大體可分為以下幾個步驟。
創(chuàng)建自定義異常:
在方法中通過throw關(guān)鍵字拋出異常對象:
如果在當(dāng)前拋出異常的方法中處理異常傻昙,可以使用try-catch語句捕獲并處理闺骚;否則在方法的聲明處通過throws關(guān)鍵字指明要拋出給方法調(diào)用者的異常,繼續(xù)進(jìn)行下一步操作妆档。
在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常僻爽。
總結(jié)
Java異常是Java提供的一種識別及響應(yīng)錯誤的一致性機(jī)制。
Java異常機(jī)制可以使程序中異常處理代碼和正常業(yè)務(wù)代碼分離贾惦,降低耦合度胸梆。保證程序代碼更加優(yōu)雅,并提高程序健壯性须板。在有效使用異常的情況下碰镜,異常能清晰的回答what, where, why這3個問題:異常類型回答了“什么”被拋出,異常堆棧跟蹤回答了“在哪“拋出逼纸,異常信息回答了“為什么“會拋出洋措。
Thanks
《Java 編程思想》
http://blog.csdn.net/you_off3/article/details/7572471
https://www.cnblogs.com/skywang12345/p/3544168.html#a2
http://www.importnew.com/1701.html