4.2 拋出異常
任何Java代碼都可以拋出異常,如:自己編寫的代碼沿彭、來自Java開發(fā)環(huán)境包中代碼,或者Java運(yùn)行時(shí)系統(tǒng)朦佩。無論是誰并思,都可以通過Java的throw語句拋出異常。從方法中拋出的任何異常都必須使用throws子句语稠。
1. throws拋出異常
如果一個(gè)方法可能會(huì)出現(xiàn)異常宋彼,但沒有能力處理這種異常,可以在方法聲明處用throws子句來聲明拋出異常仙畦。例如汽車在運(yùn)行時(shí)可能會(huì)出現(xiàn)故障输涕,汽車本身沒辦法處理這個(gè)故障,那就讓開車的人來處理慨畸。
throws語句用在方法定義時(shí)聲明該方法要拋出的異常類型莱坎,如果拋出的是Exception異常類型,則該方法被聲明為拋出所有的異常寸士。多個(gè)異抽苁玻可使用逗號(hào)分割碴卧。throws語句的語法格式為:
methodname throws Exception1,Exception2,..,ExceptionN
{
}
方法名后的throws Exception1,Exception2,...,ExceptionN 為聲明要拋出的異常列表。當(dāng)方法拋出異常列表的異常時(shí)乃正,方法將不對(duì)這些類型及其子類類型的異常作處理住册,而拋向調(diào)用該方法的方法,由他去處理瓮具。例如:
import java.lang.Exception;
public class TestException {
static void pop() throws NegativeArraySizeException {
// 定義方法并拋出NegativeArraySizeException異常
int[] arr = new int[-3]; // 創(chuàng)建數(shù)組
}
public static void main(String[] args) { // 主方法
try { // try語句處理異常信息
pop(); // 調(diào)用pop()方法
} catch (NegativeArraySizeException e) {
System.out.println("pop()方法拋出的異常");// 輸出異常信息
}
}
}
使用throws關(guān)鍵字將異常拋給調(diào)用者后荧飞,如果調(diào)用者不想處理該異常,可以繼續(xù)向上拋出名党,但最終要有能夠處理該異常的調(diào)用者叹阔。
pop方法沒有處理異常NegativeArraySizeException,而是由main函數(shù)來處理兑巾。
Throws拋出異常的規(guī)則:
- 如果是不可查異常(unchecked exception)条获,即Error、RuntimeException或它們的子類蒋歌,那么可以不使用throws關(guān)鍵字來聲明要拋出的異常帅掘,編譯仍能順利通過,但在運(yùn)行時(shí)會(huì)被系統(tǒng)拋出堂油。
2)必須聲明方法可拋出的任何可查異常(checked exception)修档。即如果一個(gè)方法可能出現(xiàn)受可查異常,要么用try-catch語句捕獲府框,要么用throws子句聲明將它拋出吱窝,否則會(huì)導(dǎo)致編譯錯(cuò)誤
3)僅當(dāng)拋出了異常,該方法的調(diào)用者才必須處理或者重新拋出該異常迫靖。當(dāng)方法的調(diào)用者無力處理該異常的時(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();}
}
** 判斷一個(gè)方法可能會(huì)出現(xiàn)異常的依據(jù)如下:**
1)方法中有throw語句。例如辣卒,以上method7()方法的catch代碼塊有throw語句掷贾。
2)調(diào)用了其他方法,其他方法用throws子句聲明拋出某種異常荣茫。例如想帅,method3()方法調(diào)用了method1()方法,method1()方法聲明拋出IOException啡莉,因此港准,在method3()方法中可能會(huì)出現(xiàn)IOException。
2. 使用throw拋出異常
throw總是出現(xiàn)在函數(shù)體中咧欣,用來拋出一個(gè)Throwable類型的異常浅缸。程序會(huì)在throw語句后立即終止,它后面的語句執(zhí)行不到魄咕,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里向外尋找含有與其匹配的catch子句的try塊衩椒。
我們知道,異常是異常類的實(shí)例對(duì)象哮兰,我們可以創(chuàng)建異常類的實(shí)例對(duì)象通過throw語句拋出毛萌。該語句的語法格式為:
throw new exceptionname;
例如拋出一個(gè)IOException類的異常對(duì)象:
throw new IOException;
要注意的是,throw 拋出的只能夠是可拋出類Throwable 或者其子類的實(shí)例對(duì)象喝滞。下面的操作是錯(cuò)誤的:
throw new String("exception");
這是因?yàn)镾tring 不是Throwable 類的子類阁将。
如果拋出了檢查異常,則還應(yīng)該在方法頭部聲明方法可能拋出的異常類型右遭。該方法的調(diào)用者也必須檢查處理拋出的異常做盅。
如果所有方法都層層上拋獲取的異常,最終JVM會(huì)進(jìn)行處理窘哈,處理也很簡單吹榴,就是打印異常消息和堆棧信息。如果拋出的是Error或RuntimeException滚婉,則該方法的調(diào)用者可選擇處理該異常腊尚。
package Test;
import java.lang.Exception;
public class TestException {
static int quotient(int x, int y) throws MyException { // 定義方法拋出異常
if (y < 0) { // 判斷參數(shù)是否小于0
throw new MyException("除數(shù)不能是負(fù)數(shù)"); // 異常信息
}
return x/y; // 返回值
}
public static void main(String args[]) { // 主方法
int a =3;
int b =0;
try { // try語句包含可能發(fā)生異常的語句
int result = quotient(a, b); // 調(diào)用方法quotient()
} catch (MyException e) { // 處理自定義異常
System.out.println(e.getMessage()); // 輸出異常信息
} catch (ArithmeticException e) { // 處理ArithmeticException異常
System.out.println("除數(shù)不能為0"); // 輸出提示信息
} catch (Exception e) { // 處理其他異常
System.out.println("程序發(fā)生了其他的異常"); // 輸出提示信息
}
}
}
class MyException extends Exception { // 創(chuàng)建自定義異常類
String message; // 定義String類型變量
public MyException(String ErrorMessagr) { // 父類方法
message = ErrorMessagr;
}
public String getMessage() { // 覆蓋getMessage()方法
return message;
}
}
4.3 異常鏈
如果調(diào)用quotient(3,-1),將發(fā)生MyException異常满哪,程序調(diào)轉(zhuǎn)到catch (MyException e)代碼塊中執(zhí)行;
-
如果調(diào)用quotient(5,0)劝篷,將會(huì)因“除數(shù)為0”錯(cuò)誤引發(fā)ArithmeticException異常哨鸭,屬于運(yùn)行時(shí)異常類,由Java運(yùn)行時(shí)系統(tǒng)自動(dòng)拋出娇妓。quotient()方法沒有捕捉ArithmeticException異常像鸡,Java運(yùn)行時(shí)系統(tǒng)將沿方法調(diào)用棧查到main方法,將拋出的異常上傳至quotient()方法的調(diào)用者:
int result = quotient(a, b); // 調(diào)用方法quotient()
由于該語句在try監(jiān)控區(qū)域內(nèi),因此傳回的“除數(shù)為0”的ArithmeticException異常由Java運(yùn)行時(shí)系統(tǒng)拋出只估,并匹配catch子句:catch (ArithmeticException e) { // 處理ArithmeticException異常 System.out.println("除數(shù)不能為0"); // 輸出提示信息 }
處理結(jié)果是輸出“除數(shù)不能為0”志群。Java這種向上傳遞異常信息的處理機(jī)制,形成異常鏈蛔钙。
Java方法拋出的可查異常將依據(jù)調(diào)用棧锌云、沿著方法調(diào)用的層次結(jié)構(gòu)一直傳遞到具備處理能力的調(diào)用方法,最高層次到main方法為止吁脱。如果異常傳遞到main方法桑涎,而main不具備處理能力,也沒有通過throws聲明拋出該異常兼贡,將可能出現(xiàn)編譯錯(cuò)誤攻冷。
3)如還有其他異常發(fā)生,將使用catch (Exception e)捕捉異常遍希。由于Exception是所有異常類的父類等曼,如果將catch (Exception e)代碼塊放在其他兩個(gè)代碼塊的前面,后面的代碼塊將永遠(yuǎn)得不到執(zhí)行凿蒜,就沒有什么意義了禁谦,所以catch語句的順序不可掉換。
4.4 Throwable類中的常用方法
注意:catch關(guān)鍵字后面括號(hào)中的Exception類型的參數(shù)e篙程。Exception就是try代碼塊傳遞給catch代碼塊的變量類型枷畏,e就是變量名。catch代碼塊中語句"e.getMessage();"用于輸出錯(cuò)誤性質(zhì)虱饿。通常異常處理常用3個(gè)函數(shù)來獲取異常的有關(guān)信息:
getCause():返回拋出異常的原因拥诡。如果 cause 不存在或未知,則返回 null氮发。
getMeage():返回異常的消息信息渴肉。
printStackTrace():對(duì)象的堆棧跟蹤輸出至錯(cuò)誤輸出流,作為字段 System.err 的值爽冕。
有時(shí)為了簡單會(huì)忽略掉catch語句后的代碼仇祭,這樣try-catch語句就成了一種擺設(shè),一旦程序在運(yùn)行過程中出現(xiàn)了異常颈畸,就會(huì)忽略處理異常乌奇,而錯(cuò)誤發(fā)生的原因很難查找。
5.Java常見異常
在Java中提供了一些異常用來描述經(jīng)常發(fā)生的錯(cuò)誤眯娱,對(duì)于這些異常礁苗,有的需要程序員進(jìn)行捕獲處理或聲明拋出,有的是由Java虛擬機(jī)自動(dòng)進(jìn)行捕獲處理徙缴。Java中常見的異常類:
1. runtimeException子類:
1试伙、 java.lang.ArrayIndexOutOfBoundsException 數(shù)組索引越界異常。當(dāng)對(duì)數(shù)組的索引值為負(fù)數(shù)或大于等于數(shù)組大小時(shí)拋出。 2疏叨、java.lang.ArithmeticException 算術(shù)條件異常潘靖。譬如:整數(shù)除零等。 3蚤蔓、java.lang.NullPointerException 空指針異常卦溢。當(dāng)應(yīng)用試圖在要求使用對(duì)象的地方使用了null時(shí),拋出該異常昌粤。譬如:調(diào)用null對(duì)象的實(shí)例方法既绕、訪問null對(duì)象的屬性、計(jì)算null對(duì)象的長度涮坐、使用throw語句拋出null等等 4凄贩、java.lang.ClassNotFoundException 找不到類異常。當(dāng)應(yīng)用試圖根據(jù)字符串形式的類名構(gòu)造類袱讹,而在遍歷CLASSPAH之后找不到對(duì)應(yīng)名稱的class文件時(shí)疲扎,拋出該異常。
5捷雕、java.lang.NegativeArraySizeException 數(shù)組長度為負(fù)異常
6椒丧、java.lang.ArrayStoreException 數(shù)組中包含不兼容的值拋出的異常
7、java.lang.SecurityException 安全性異常
8救巷、java.lang.IllegalArgumentException 非法參數(shù)異常
2.IOException
IOException:操作輸入流和輸出流時(shí)可能出現(xiàn)的異常壶熏。
EOFException 文件已結(jié)束異常
FileNotFoundException 文件未找到異常
- 其他
ClassCastException 類型轉(zhuǎn)換異常類
ArrayStoreException 數(shù)組中包含不兼容的值拋出的異常
SQLException 操作[數(shù)據(jù)庫]異常類
NoSuchFieldException 字段未找到異常
NoSuchMethodException 方法未找到拋出的異常
NumberFormatException 字符串轉(zhuǎn)換為數(shù)字拋出的異常
StringIndexOutOfBoundsException 字符串索引超出范圍拋出的異常
IllegalAccessException 不允許訪問某類異常
InstantiationException 當(dāng)應(yīng)用程序試圖使用Class類中的newInstance()方法創(chuàng)建一個(gè)類的實(shí)例,而指定的類對(duì)象無法被實(shí)例化時(shí)浦译,拋出該異常
6.自定義異常
使用Java內(nèi)置的異常類可以描述在編程時(shí)出現(xiàn)的大部分異常情況棒假。除此之外,用戶還可以自定義異常精盅。用戶自定義異常類帽哑,只需繼承Exception類即可。 在程序中使用自定義異常類叹俏,大體可分為以下幾個(gè)步驟妻枕。 (1)創(chuàng)建自定義異常類。 (2)在方法中通過throw關(guān)鍵字拋出異常對(duì)象粘驰。 (3)如果在當(dāng)前拋出異常的方法中處理異常屡谐,可以使用try-catch語句捕獲并處理;否則在方法的聲明處通過throws關(guān)鍵字指明要拋出給方法調(diào)用者的異常蝌数,繼續(xù)進(jìn)行下一步操作康嘉。 (4)在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常。
在上面的“使用throw拋出異匙亚埃”例子已經(jīng)提到了。