異常指程序運(yùn)行過程中出現(xiàn)的非正常現(xiàn)象冬三,例如用戶輸入錯誤匀油、除數(shù)為零、需要處理的 文件不存在勾笆、數(shù)組下標(biāo)越界等敌蚜。
所謂異常處理,就是指程序在出現(xiàn)問題時依然可以正確的執(zhí)行完窝爪。
Java 是采用面向?qū)ο蟮姆绞絹硖幚懋惓5某诔怠L幚磉^程:
- 拋出異常:在執(zhí)行一個方法時,如果發(fā)生異常蒲每,則這個方法生成代表該異常的一個 對象纷跛,停止當(dāng)前執(zhí)行路徑,并把異常對象提交給 JRE邀杏。
- 捕獲異常:JRE 得到該異常后贫奠,尋找相應(yīng)的代碼來處理該異常。JRE 在方法的調(diào)用 棧中查找,從生成異常的方法開始回溯叮阅,直到找到相應(yīng)的異常處理代碼為止刁品。
一、異常分類
Java 對異常進(jìn)行了分類浩姥,不同類型的異常分別用不同的 Java 類表示挑随,所有異常的根類 為 java.lang.Throwable,Throwable 下面又派生了兩個子類:Error 和 Exception勒叠。
1. Error
Error 是程序無法處理的錯誤兜挨,表示運(yùn)行應(yīng)用程序中較嚴(yán)重問題。大多數(shù)錯誤與代碼編 寫者執(zhí)行的操作無關(guān)眯分,而表示代碼運(yùn)行時 JVM(Java 虛擬機(jī))出現(xiàn)的問題拌汇。例如,Java 虛擬機(jī)運(yùn)行錯誤(Virtual MachineError)弊决,當(dāng) JVM 不再有繼續(xù)執(zhí)行操作所需的內(nèi)存資源時噪舀,將出現(xiàn) OutOfMemoryError。這些異常發(fā)生時飘诗,Java 虛擬機(jī)(JVM)一般會選擇線 程終止与倡。 Error 表明系統(tǒng) JVM 已經(jīng)處于不可恢復(fù)的崩潰狀態(tài)中。我們不需要管他昆稿。
2. Exception
Exception 是程序本身能夠處理的異常纺座,如:空指針異常(NullPointerException)、數(shù) 組 下 標(biāo) 越 界 異 常 ( ArrayIndexOutOfBoundsException )溉潭、類 型 轉(zhuǎn) 換 異 常 (ClassCastException)净响、算術(shù)異常(ArithmeticException)等。Exception 類是所有異常類的父類喳瓣,其子類對應(yīng)了各種各樣可能出現(xiàn)的異常事件馋贤。
通常 Java 的異常可分為:
- RuntimeException 運(yùn)行時異常
- CheckedException 已檢查異常
3. RuntimeException
派生于 RuntimeException 的異常畏陕,如被 0 除掸掸、數(shù)組下標(biāo)越界、空指針等蹭秋,其產(chǎn)生比較頻繁,處理麻煩堤撵,如果顯式的聲明或捕獲將會對程序可讀性和運(yùn)行效率影響很大仁讨。 因此 由系統(tǒng)自動檢測并將它們交給缺省的異常處理程序(用戶可不必對其處理)。
這類異常通常是由編程錯誤導(dǎo)致的实昨,所以在編寫程序時洞豁,并不要求必須使用異常處理機(jī) 制來處理這類異常,經(jīng)常需要通過增加“邏輯處理來避免這些異常”。
常見的運(yùn)行時異常:
- ArithmeticException 異常:試圖除以 0
public class Test3 {
public static void main(String[ ] args) {
int b=0;
System.out.println(1/b);
}
}
- NullPointerException 異常
public class Test4 {
public static void main(String[ ] args) {
String str=null;
System.out.println(str.charAt(0));
}
}
- ClassCastException 異常
class Animal{
}
class Dog extends Animal{
}
class Cat extends Animal{
}
public class Test5 {
public static void main(String[ ] args) {
Animal a=new Dog();
Cat c=(Cat)a;
}
}
- ArrayIndexOutOfBoundsException 異常
public class Test6 {
public static void main(String[ ] args) {
int[ ] arr = new int[5];
System.out.println(arr[5]);
}
}
- NumberFormatException 異常
public class Test7 {
public static void main(String[ ] args) {
String str = "1234abcf";
System.out.println(Integer.parseInt(str));
}
}
4. CheckedException
所有不是 RuntimeException 的異常丈挟,統(tǒng)稱為 Checked Exception刁卜,又被稱為“已檢 查異常”曙咽,如 IOException蛔趴、SQLException 等以及用戶自定義的 Exception 異常。 這類 異常在編譯時就必須做出處理例朱,否則無法通過編譯孝情。
異常的處理方式有兩種:使用“try/catch”捕獲異常、使用“throws” 聲明異常洒嗤。
二箫荡、異常捕獲
捕獲異常是通過 3 個關(guān)鍵詞來實(shí)現(xiàn)的:try-catch-finally。用 try 來執(zhí)行一段程序渔隶,如 果出現(xiàn)異常羔挡,系統(tǒng)拋出一個異常,可以通過它的類型來捕捉(catch)并處理它间唉,最后一步 是通過 finally 語句為異常處理提供一個統(tǒng)一的出口绞灼,finally 所指定的代碼都要被執(zhí)行 (catch 語句可有多條;finally 語句最多只能有一條终吼,根據(jù)自己的需要可有可無)镀赌。
try{
可能出現(xiàn)異常的代碼
}catch(異常類型 變量名){
出現(xiàn)異常時執(zhí)行的代碼
}....catch(異常類型 變量名){
出現(xiàn)異常時執(zhí)行的代碼
}finally{
最后要執(zhí)行的代碼
}
注意:
- 一個try后可以有1~n個catch
- catch是從上到下依次判斷執(zhí)行,try中沒有出現(xiàn)異常际跪,不會執(zhí)行catch判斷捕獲商佛。一旦出現(xiàn)異常,try中后面的代碼不會執(zhí)行
- 如果catch中捕獲的異常類型比較大姆打,應(yīng)放在最后
- finally:當(dāng)前try ... catch的結(jié)構(gòu)執(zhí)行結(jié)束后良姆,會執(zhí)行finally中的代碼(一般為釋放資源的代碼)
例:
public class Test8 {
public static void main(String[ ] args) {
FileReader reader = null;
try {
reader = new FileReader("d:/a.txt");
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
三、聲明異常
當(dāng) CheckedException 產(chǎn)生時幔戏,不一定立刻處理它玛追,可以再把異常 throws 出去。
在方法中使用 try-catch-finally 是由這個方法來處理異常闲延。但是在一些情況下痊剖,當(dāng)前方法并不需要處理發(fā)生的異常,而是向上傳遞給調(diào)用它的方法處理垒玲。
如果一個方法中可能產(chǎn)生某種異常陆馁,但是并不能確定如何處理這種異常,則應(yīng)根據(jù)異常規(guī)范在方法的首部聲明該方法可能拋出的異常合愈。
如果一個方法拋出多個已檢查異常叮贩,就必須在方法的首部列出所有的異常击狮,之間以逗號隔開。
public static void readFile(String fileName) throws FileNotFoundException, IOException {
FileReader in = new FileReader(fileName);
int tem = 0;
try {
tem = in.read();
while (tem != -1) {
System.out.print((char) tem);
tem = in.read();
}
} finally {
if (in != null) {
in.close();
}
}
}
四益老、try-with-resource 自動關(guān)閉 Closable 接口的資源
public class Test8 {
public static void main(String[] args) {
try (FileReader reader = new FileReader("d:/a.txt");) { //try-with-resource
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
五彪蓬、自定義異常
- 在程序中,可能會遇到 JDK 提供的任何標(biāo)準(zhǔn)異常類都無法充分描述清楚我們想要 表達(dá)的問題捺萌,這種情況下可以創(chuàng)建自己的異常類档冬,即自定義異常類。
- 自定義異常類只需從 Exception 類或者它的子類派生一個子類即可互婿。
- 自定義異常類如果繼承 Exception 類捣郊,則為受檢查異常,必須對其進(jìn)行處理慈参;如果不想處理呛牲,可以讓自定義異常類繼承運(yùn)行時異常 RuntimeException 類。
- 習(xí)慣上驮配,自定義異常類應(yīng)該包含 2 個構(gòu)造器:一個是默認(rèn)的構(gòu)造器娘扩,另一個是帶 有詳細(xì)信息的構(gòu)造器。
class IllegalAgeException extends Exception {
public IllegalAgeException() {
}//帶有詳細(xì)信息的構(gòu)造器壮锻,信息存儲在 message 中
public IllegalAgeException(String message) {
super(message);
}
}
自定義異常的使用:
public void setAge(int age) throws IllegalAgeException {
if (age < 0) {
throw new IllegalAgeException("人的年齡不應(yīng)該為負(fù)數(shù)");
}
this.age = age;
}