異常簡(jiǎn)介
異常指阻止當(dāng)前方法繼續(xù)執(zhí)行的問(wèn)題像街,如:文件找不到筹裕、網(wǎng)絡(luò)連接失敗、非法參數(shù)等椎木。發(fā)現(xiàn)異常的理想時(shí)期是編譯階段,然而編譯期間.不能找出所有的異常,余下的問(wèn)題須在運(yùn)行期間.
java中的異常分為可查異常和不可查異常
- 可查異常
即編譯時(shí)異常,指編譯器在編譯時(shí)可以發(fā)現(xiàn)的錯(cuò)誤违柏,程序在運(yùn)行時(shí)很容易出現(xiàn)的異常狀況,這些異诚阕担可以預(yù)計(jì)勇垛,所以在編譯階段就必須手動(dòng)進(jìn)行捕捉處理,即要么用try-catch語(yǔ)句捕獲它士鸥,要么用throws子句聲明拋出闲孤,否則編譯無(wú)法通過(guò)。如IOException烤礁、SQLException以及用戶(hù)自定義的Exception異常 - 不可查異常
不可查異常包括運(yùn)行時(shí)異常(runtimeException)和錯(cuò)誤(error),他們都是在程序運(yùn)行時(shí)出現(xiàn)的讼积。異常和錯(cuò)誤的區(qū)別:異常能被程序本身可以處理,錯(cuò)誤是無(wú)法處理
運(yùn)行時(shí)異常(runtimeException)指的是程序在運(yùn)行時(shí)才會(huì)出現(xiàn)的錯(cuò)誤脚仔,由程序員自己分析代碼決定是否用try...catch進(jìn)行捕捉處理勤众。如nullpointerException,classcastException,indexoutofboundsException。
錯(cuò)誤(error)鲤脏,是程序無(wú)法處理的錯(cuò)誤们颜,表示運(yùn)行應(yīng)用程序中較嚴(yán)重問(wèn)題,如系統(tǒng)崩潰吕朵,虛擬機(jī)錯(cuò)誤,動(dòng)態(tài)連接失敗等窥突。大多數(shù)錯(cuò)誤與代碼編寫(xiě)者執(zhí)行的操作無(wú)關(guān)努溃,而表示代碼運(yùn)行時(shí)JVM(Java虛擬機(jī))出現(xiàn)的問(wèn)題。例如阻问,Java虛擬機(jī)運(yùn)行錯(cuò)誤(VirtualMachineError)梧税,當(dāng)JVM不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時(shí),將出現(xiàn)OutOfMemoryError称近。這些異常發(fā)生時(shí)第队,Java虛擬機(jī)(JVM)一般會(huì)選擇線(xiàn)程終止。這些錯(cuò)誤表示故障發(fā)生于虛擬機(jī)自身刨秆、或者發(fā)生在虛擬機(jī)試圖執(zhí)行應(yīng)用時(shí)凳谦,如Java虛擬機(jī)運(yùn)行錯(cuò)誤(VirtualMachineError)、類(lèi)定義錯(cuò)(NoClassDefFoundError)等衡未。這些錯(cuò)誤是不可查的晾蜘,即不需要捕獲和處理,因?yàn)樗鼈冊(cè)趹?yīng)用程序的控制和處理能力之外,而且絕大多數(shù)是程序運(yùn)行時(shí)不允許出現(xiàn)的狀況眠屎。對(duì)于設(shè)計(jì)合理的應(yīng)用程序來(lái)說(shuō),即使確實(shí)發(fā)生了錯(cuò)誤肆饶,本質(zhì)上也不應(yīng)該試圖去處理它所引起的異常狀況改衩。
Java異常類(lèi)層次結(jié)構(gòu)圖:
從上圖可以看出Java通過(guò)API中Throwable類(lèi)的眾多子類(lèi)描述各種不同的異常。因而驯镊,Java異常都是對(duì)象葫督,是Throwable子類(lèi)的實(shí)例.
在Java中,所有的異常都有一個(gè)共同的祖先Throwable(可拋出)板惑。Throwable指定代碼中可用異常傳播機(jī)制通過(guò)Java應(yīng)用程序傳輸?shù)娜魏螁?wèn)題的共性橄镜。
異常處理機(jī)制
當(dāng)異常發(fā)生時(shí),將使用new在堆上創(chuàng)建一個(gè)異常對(duì)象,對(duì)于這個(gè)異常對(duì)象,有兩種處理方式.
1.使用throw關(guān)鍵字將異常對(duì)象拋出,則當(dāng)前執(zhí)行路徑被終止,異常處理機(jī)制將在其他地方尋找catch塊對(duì)異常進(jìn)行處理.
2.使用try...catch在當(dāng)前邏輯中就進(jìn)行捕獲處理.
throws 和throw
- throws: 一個(gè)方法在聲明時(shí)可以使用throws關(guān)鍵字聲明可能會(huì)產(chǎn)生的若干異常。
- throw: 拋出異常冯乘,并退出當(dāng)前方法或作用域洽胶。
用throws聲明要拋出的異常,實(shí)際可以不拋出裆馒。而用throw拋出的異常也可以不聲明姊氓。不過(guò)Java鼓勵(lì)程序員把可能會(huì)拋出的異常提前聲明,這是一種優(yōu)雅的做法喷好。
自定義異常
Java的異常體系不可能包括所有的異常情況翔横,所以可以自己定義異常類(lèi)來(lái)表示程序中可能會(huì)遇到的特定問(wèn)題。
public class MyException extends RuntimeException {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
在 MyException 這個(gè)自定義異常中梗搅,定義了兩個(gè)構(gòu)造器禾唁。一個(gè)是默認(rèn)構(gòu)造器效览,一個(gè)接收一個(gè)字符串作為參數(shù)。在第二個(gè)構(gòu)造器中荡短,可以看出調(diào)用了基類(lèi)構(gòu)造器丐枉,所傳字符串可以通過(guò)getMessage()方法獲取。
public class ExceptionTest {
public static void f(){
System.out.println("Throwing Exception from f()");
throw new MyException();
}
public static void g(){
System.out.println("Throwing Exception from g()");
throw new MyException("Originated in g()");
}
public static void main(String[] argv) throws Exception {
try{
f();
}catch(MyException e){
System.out.println(e.getMessage());
e.printStackTrace(System.out);
}
}
}
在main函數(shù)中調(diào)用g(),運(yùn)行結(jié)果如下
可以總結(jié)出以下兩個(gè)函數(shù):
- getMessage():獲取一些描述性信息
- printStackTrace():從方法調(diào)用出到異常拋出處的方法調(diào)用序列
重新拋出異常
有時(shí)希望把捕獲的異常重新拋出肢预,在catch中已經(jīng)得到了對(duì)當(dāng)前異常對(duì)象的引用矛洞,可以將其重新拋出。
public class ExceptionTest {
public static void g() {
throw new MyException("Originated in g()");
}
public static void h() {
try {
g();
} catch (MyException e) {
System.out.println("An Exception was thrown from g()");
throw e;
}
}
public static void k() throws Exception {
try {
g();
} catch (MyException e) {
System.out.println("An Exception was thrown from g()");
throw (Exception) e.fillInStackTrace();
}
}
public static void main(String[] argv) throws Exception {
try {
h();
} catch (MyException e) {
System.out.println(e.getMessage());
e.printStackTrace(System.out);
}
System.out.println();
try {
k();
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace(System.out);
}
}
}
從運(yùn)行結(jié)果可以看出烫映,如果只是將異常拋出沼本,那么printStackTrace()顯示的仍是原來(lái)拋出點(diǎn)的調(diào)用棧信息,并非重新拋出點(diǎn)的信息锭沟,若想更新信息抽兆,可以調(diào)用
fillInStackTrace()方法,它通過(guò)把當(dāng)前調(diào)用棧信息填入原來(lái)那個(gè)異常對(duì)象而建立族淮。這樣調(diào)用fillInStackTrace()的那一行就會(huì)新的異常發(fā)生點(diǎn)辫红。
使用finally清理
在java中finally的存在并不是為了釋放內(nèi)存資源,因?yàn)閖ava有垃圾回收機(jī)制祝辣,因此需要java釋放的資源主要是:已經(jīng)打開(kāi)的文件或網(wǎng)絡(luò)連接等贴妻。
在try中無(wú)論有沒(méi)有捕獲異常,finally都會(huì)被執(zhí)行蝙斜。