異常類層次結(jié)構(gòu)圖:
在 Java 中钉疫,所有的異常都有一個(gè)共同的祖先 Throwable(可拋出)。
Throwable:
有兩個(gè)重要的子類:Exception(異常)和 Error(錯(cuò)誤)粒竖,二者都是 Java 異常處理的重要子類宏赘,各自都有好多子類蒋荚。
Error(錯(cuò)誤):
是程序無(wú)法處理的錯(cuò)誤疾棵,表示運(yùn)行應(yīng)用程序中較嚴(yán)重問(wèn)題戈钢。
Exception(異常):
是程序本身可以處理的異常。
常用異常
(1是尔、)OutOfMemoryError 內(nèi)存溢出異常
(2殉了、)ArrayIndexOutOfBoundsException 數(shù)組越界異常
(3、)NullPointerException 空指針異常
(4拟枚、)ArithmeticException 數(shù)字異常
(5薪铜、)ClassCastException 類型轉(zhuǎn)換異常類
(6、)SQLException 操作數(shù)據(jù)庫(kù)異常類
(7恩溅、)NoSuchMethodException 方法未找到拋出的異常
(8隔箍、)IOException 操作輸入流和輸出流時(shí)可能出現(xiàn)的異常
(9、)ClassNotFoundException 找不到類異常
Exception 這種異常分兩大類運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常(編譯異常)脚乡。程序中應(yīng)當(dāng)盡可能去處理這些異常蜒滩。
運(yùn)行時(shí)異常:都是RuntimeException類及其子類異常,如NullPointerException(空指針異常)奶稠、IndexOutOfBoundsException(下標(biāo)越界異常)等俯艰,這些異常是不檢查異常,程序中可以選擇捕獲處理锌订,也可以不處理竹握。這些異常一般是由程序邏輯錯(cuò)誤引起的,程序應(yīng)該從邏輯角度盡可能避免這類異常的發(fā)生瀑志。
運(yùn)行時(shí)異常的特點(diǎn):
是Java編譯器不會(huì)檢查它涩搓,也就是說(shuō),當(dāng)程序中可能出現(xiàn)這類異常劈猪,即使沒(méi)有用try-catch語(yǔ)句捕獲它昧甘,也沒(méi)有用throws子句聲明拋出它,也會(huì)編譯通過(guò)战得。
非運(yùn)行時(shí)異常 (編譯異常):
是RuntimeException以外的異常充边,類型上都屬于Exception類及其子類。從程序語(yǔ)法角度講是必須進(jìn)行處理的異常常侦,如果不處理浇冰,程序就不能編譯通過(guò)。如IOException聋亡、SQLException等以及用戶自定義的Exception異常肘习,一般情況下不自定義檢查異常。
處理異常機(jī)制
在 Java 應(yīng)用程序中坡倔,異常處理機(jī)制為:拋出異常漂佩,捕捉異常脖含。
異常通過(guò)try-catch語(yǔ)句捕獲。其一般語(yǔ)法形式為:
try {
// 可能會(huì)發(fā)生異常的程序代碼
} catch (Type1 id1){
// 捕獲并處置try拋出的異常類型Type1
}
catch (Type2 id2){
//捕獲并處置try拋出的異常類型Type2
}
把可能發(fā)生錯(cuò)誤的代碼放在關(guān)鍵詞try后面的大括號(hào)中投蝉,運(yùn)行時(shí)系統(tǒng)試圖尋找匹配的catch子句以捕獲異常养葵。若有匹配的catch子句,則運(yùn)行其異常處理代碼瘩缆,try-catch語(yǔ)句結(jié)束关拒。
匹配的原則是:如果拋出的異常對(duì)象屬于catch子句的異常類,或者屬于該異常類的子類庸娱,則認(rèn)為生成的異常對(duì)象與catch塊捕獲的異常類型相匹配着绊。
try {
div(4,0);
System.out.println("執(zhí)行可能存在問(wèn)題的代碼");
} catch (Exception e) {
e.printStackTrace();//打印異常 沒(méi)有的話會(huì)自動(dòng)執(zhí)行下面的程序這個(gè)異常會(huì)濾過(guò)
System.out.println(e.getMessage());//這個(gè)是輸出異常信息(是什么錯(cuò)誤)
System.out.println("捕獲異常");
}
throw 是聲明這個(gè)方法的調(diào)用存在異常情況,調(diào)用者需采取捕獲處理或繼續(xù)向外拋的操作才能過(guò)編譯
public static int div(int a, int b) throws Exception {// 為了告訴我這個(gè)方法有問(wèn)題 提前拋出異常
1. 當(dāng)這段代碼出現(xiàn)問(wèn)題時(shí)涌韩,jvm會(huì)創(chuàng)建一個(gè)異常對(duì)象并拋給調(diào)用者 (這里指Main函數(shù))
2. 調(diào)用者接受到異常之后不能處理的話畔柔,繼續(xù)往上拋,直到拋給jvm臣樱,最終將異常信息輸出到控制臺(tái)
if (b == 0){
throw new ArithmeticException("除以0了,逗比");
}
return a / b;//throw new ArithmeticException()腮考; 算數(shù)異常 這里運(yùn)行到b時(shí)雇毫,發(fā)現(xiàn)b是0,就自動(dòng)拋出異常
}
多個(gè)異常捕獲踩蔚,異常對(duì)象存在父子關(guān)系時(shí)棚放,要求父類異常類型必須寫(xiě)在下方
多個(gè)異常可以合并在同一個(gè)catch塊
try {
computer.setStatus("進(jìn)水");
}catch (DownException e){
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}finally {//不管出現(xiàn)任何異常的情況下都會(huì)走這個(gè)代碼塊
}
}
小結(jié):
try 塊:用于捕獲異常馅闽。其后可接零個(gè)或多個(gè)catch塊飘蚯,如果沒(méi)有catch塊,則必須跟一個(gè)finally塊福也。
catch 塊:用于處理try捕獲到的異常局骤。
finally 塊:無(wú)論是否捕獲或處理異常,finally塊里的語(yǔ)句都會(huì)被執(zhí)行暴凑。當(dāng)在try塊或catch塊中遇到return語(yǔ)句時(shí)峦甩,finally語(yǔ)句塊將在方法返回之前被執(zhí)行。在以下4種特殊情況下现喳,finally塊不會(huì)被執(zhí)行:
1)在finally語(yǔ)句塊中發(fā)生了異常凯傲。
2)在前面的代碼中用了System.exit()退出程序。
3)程序所在的線程死亡嗦篱。
4)關(guān)閉CPU冰单。
try、catch灸促、finally語(yǔ)句塊的執(zhí)行順序:
1)當(dāng)try沒(méi)有捕獲到異常時(shí):try語(yǔ)句塊中的語(yǔ)句逐一被執(zhí)行诫欠,程序?qū)⑻^(guò)catch語(yǔ)句塊涵卵,執(zhí)行finally語(yǔ)句塊和其后的語(yǔ)句;
2)當(dāng)try捕獲到異常呕诉,catch語(yǔ)句塊里沒(méi)有處理此異常的情況:當(dāng)try語(yǔ)句塊里的某條語(yǔ)句出現(xiàn)異常時(shí)缘厢,而沒(méi)有處理此異常的catch語(yǔ)句塊時(shí),此異常將會(huì)拋給JVM處理甩挫,finally語(yǔ)句塊里的語(yǔ)句還是會(huì)被執(zhí)行贴硫,但finally語(yǔ)句塊后的語(yǔ)句不會(huì)被執(zhí)行;
3)當(dāng)try捕獲到異常伊者,catch語(yǔ)句塊里有處理此異常的情況:在try語(yǔ)句塊中是按照順序來(lái)執(zhí)行的英遭,當(dāng)執(zhí)行到某一條語(yǔ)句出現(xiàn)異常時(shí),程序?qū)⑻絚atch語(yǔ)句塊亦渗,并與catch語(yǔ)句塊逐一匹配挖诸,找到與之對(duì)應(yīng)的處理程序,其他的catch語(yǔ)句塊將不會(huì)被執(zhí)行法精,而try語(yǔ)句塊中多律,出現(xiàn)異常之后的語(yǔ)句也不會(huì)被執(zhí)行,catch語(yǔ)句塊執(zhí)行完后搂蜓,執(zhí)行finally語(yǔ)句塊里的語(yǔ)句狼荞,最后執(zhí)行finally語(yǔ)句塊后的語(yǔ)句;
Throws拋出異常的規(guī)則:
1) 如果是不可查異常(unchecked exception)帮碰,即Error相味、RuntimeException或它們的子類,那么可以不使用throws關(guān)鍵字來(lái)聲明要拋出的異常殉挽,編譯仍能順利通過(guò)丰涉,但在運(yùn)行時(shí)會(huì)被系統(tǒng)拋出。
2)必須聲明方法可拋出的任何可查異常(checked exception)斯碌。即如果一個(gè)方法可能出現(xiàn)受可查異常一死,要么用try-catch語(yǔ)句捕獲,要么用throws子句聲明將它拋出输拇,否則會(huì)導(dǎo)致編譯錯(cuò)誤
3)僅當(dāng)拋出了異常摘符,該方法的調(diào)用者才必須處理或者重新拋出該異常。當(dāng)方法的調(diào)用者無(wú)力處理該異常的時(shí)候策吠,應(yīng)該繼續(xù)拋出逛裤,而不是囫圇吞棗。
4)調(diào)用方法必須遵循任何可查異常的處理和聲明規(guī)則猴抹。若覆蓋一個(gè)方法带族,則不能聲明與覆蓋方法不同的異常。聲明的任何異常必須是被覆蓋方法所聲明異常的同類或子類蟀给。
例如:
void method1() throws IOException{} //合法
//編譯錯(cuò)誤蝙砌,必須捕獲或聲明拋出IOException
void method2(){
method1();
}
//合法阳堕,聲明拋出IOException
void method3()throws IOException {
method1();
}
//合法,聲明拋出Exception择克,IOException是Exception的子類
void method4()throws Exception {
method1();
}
//合法恬总,捕獲IOException
void method5(){
try{
method1();
}catch(IOException e){…}
}
//編譯錯(cuò)誤,必須捕獲或聲明拋出Exception
void method6(){
try{
method1();
}catch(IOException e){throw new Exception();}
}
//合法肚邢,聲明拋出Exception
void method7()throws Exception{
try{
method1();
}catch(IOException e){throw new Exception();}
}