異常處理
異常處理機(jī)制是Java
語言中一個(gè)獨(dú)特之處汪厨,它為開發(fā)穩(wěn)定的軟件系統(tǒng)提供了有力的支持。它主要使用捕獲異常和聲明拋棄異常兩種方法來處理程序中可能出現(xiàn)異常的語句塊伪煤,其中捕獲異常的方法是一種積極地處理異常的方法廓旬,而聲明拋棄異常是一種消極地處理異常的方法哥艇。當(dāng)Java
內(nèi)置的異常都不能明確地說明異常情況的時(shí)候,需要?jiǎng)?chuàng)建自己的異常胁黑。
一. 異常處理基礎(chǔ)
異常就是在程序的運(yùn)行過程中所發(fā)生的異常事件废封,它中斷指令的正常執(zhí)行。Java
提供了一種獨(dú)特地處理異常的機(jī)制丧蘸,通過異常來處理程序設(shè)計(jì)中出現(xiàn)的錯(cuò)誤漂洋。當(dāng)程序運(yùn)行出現(xiàn)異常時(shí),Java
運(yùn)行環(huán)境就用異常類Exception
的相應(yīng)子類創(chuàng)建一個(gè)異常對象力喷,并等待處理刽漂。異常對象可以調(diào)用方法得到或輸出有關(guān)異常的信息。
1. 異常類的層次
在JDK中弟孟,每個(gè)包中都定義了異常類贝咙,而所有的異常類都直接或間接地繼承于Throwable類。
2. 異常類的分類
Java
中的異常類可分為兩大類:Error
和Exception
拂募。
Error
---動態(tài)鏈接失敗庭猩,虛擬機(jī)錯(cuò)誤等,通常Java
程序不應(yīng)該捕獲這種異常没讲,也不會拋棄這種異常眯娱。
Exception
---包括運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常。
(1) 運(yùn)行時(shí)異常
繼承于RuntimeException
的類都屬于運(yùn)行時(shí)異常爬凑,例如算術(shù)異常(除零錯(cuò))徙缴、數(shù)組下標(biāo)越界異常等。由于這些異常產(chǎn)生的位置是未知的,Java
編譯器允許程序員在程序中不對它們做出處理于样。(2) 非運(yùn)行時(shí)異常
除了運(yùn)行時(shí)異常之外疏叨,其他由Exception
繼承來的異常類都是非運(yùn)行時(shí)的異常,例如FileNotFoundException
(文件未找到異常)穿剖。Java編譯器要求在程序中必須處理蚤蔓,捕獲或者聲明拋棄異常。
1.Error體系類型異常的特點(diǎn)
Error
類體系描述了Java
運(yùn)行系統(tǒng)中的內(nèi)部錯(cuò)誤以及資源耗盡的情形糊余。應(yīng)用程序不應(yīng)該拋出這種類型的對象(一般是由虛擬機(jī)拋出)秀又。如果出現(xiàn)這種錯(cuò)誤,除了盡力使程序安全退出外贬芥,在其他方面是無能為力的吐辙。所以在進(jìn)行程序設(shè)計(jì)時(shí),應(yīng)該更關(guān)注Exception體系蘸劈。
2.Exception體系類型異常的特點(diǎn)
Exception
體系包括RuntimeException
體系和其他非RuntimeException
的體系昏苏。
- (1)
RuntimeException
體系包括錯(cuò)誤的類型轉(zhuǎn)換、數(shù)組越界訪問和試圖訪問空指針等威沫。處理RuntimeException
的原則是:如果出現(xiàn)RuntimeException
贤惯,那么一定是程序員的錯(cuò)誤。例如可以通過檢查數(shù)組下標(biāo)和數(shù)組邊界來避免數(shù)組越界訪問異常棒掠。
(2) 其他(IOException等)
類異常一般是外部錯(cuò)誤孵构,例如試圖從文件尾后讀取數(shù)據(jù)等,這并不是程序本身的錯(cuò)誤句柠,而是在應(yīng)用環(huán)境中出現(xiàn)的外部錯(cuò)誤浦译。
異常的處理
java
語言中有兩種異常處理機(jī)制:捕獲異常
和聲明拋棄異常
1. 捕獲異常
當(dāng)Java
運(yùn)行環(huán)境得到一個(gè)異常對象時(shí),它將會沿著方法的調(diào)用棧逐層回溯溯职,尋找處理這一異常的代碼精盅,找到能夠處理這種類型的異常的方法后,運(yùn)行環(huán)境把當(dāng)前異常對象交給這個(gè)方法進(jìn)行處理谜酒,這一過程稱為捕獲(catch)異常
叹俏。這是積極的異常處理機(jī)制。如果Java
運(yùn)行環(huán)境找不到可以捕獲異常的方法僻族,則運(yùn)行環(huán)境將終止粘驰,相應(yīng)的Java程序也將退出。
2. 聲明拋棄異常
如果一個(gè)方法并不知道如何處理所出現(xiàn)的異常述么,則可在方法聲明時(shí)蝌数,聲明拋棄(throw)異常
。這是一種消極的異常處理機(jī)制度秘。
一. 捕獲異常
捕獲異常是通過try-catch-finally
語句實(shí)現(xiàn)的顶伞。
1. try
捕獲異常的第一步是用try{...}
選定捕獲異常的范圍,由try
所限定的代碼塊中的語句在執(zhí)行過程中可能會生成異常對象并拋棄。
2. catch
每個(gè)try
代碼塊可以伴隨一個(gè)或多個(gè)catch
語句唆貌,用于處理try
代碼塊中所生成的異常事件滑潘。catch
語句只需要一個(gè)形式參數(shù)指明它所能夠捕獲的異常類型,這個(gè)類必須是Throwable
的子類锨咙,運(yùn)行時(shí)系統(tǒng)通過參數(shù)值把被拋棄的異常對象傳遞給catch
塊语卤。catch
塊是對異常對象進(jìn)行處理的代碼,與訪問其他對象一樣酪刀,可以訪問一個(gè)異常對象的變量或調(diào)用它的方法粹舵。getMessage()
是類Throwable
所提供的方法,用來得到有關(guān)異常事件的信息蓖宦,類Throwable
還提供了方法printStackTrace()
用來跟蹤異常事件發(fā)生時(shí)執(zhí)行堆棧的內(nèi)容齐婴。
try {
...
} catch (FileNotFoundException e) {
System.out.println(e);
System.out.println("message:" + e.getMessage());
e.printStackTrace(System.out);
} catch (IOException e) {
System.out.println(e);
}
catch
語句的順序:
捕獲異常的順序和catch
語句的順序有關(guān)油猫,當(dāng)捕獲到一個(gè)異常時(shí)稠茂,剩下的catch
語句就不再進(jìn)行匹配。因此在安排catch
語句的順序時(shí)情妖,首先應(yīng)該捕獲最特殊的異常睬关,然后再逐漸一般化。也就是一般先安排子類毡证,再安排父類电爹。
3. finally
捕獲異常的最后一步是通過finally
語句為異常處理提供一個(gè)統(tǒng)一的出口,使得在控制流轉(zhuǎn)到程序的其他部分以前能夠?qū)Τ绦虻臓顟B(tài)做統(tǒng)一的管理料睛。不論在try
代碼塊中是否發(fā)生了異常事件丐箩,finally
塊中的語句都會被執(zhí)行。
二. 聲明拋棄異常
1. 聲明拋棄異常
如果在一個(gè)方法中生成了一個(gè)異常恤煞,但是這一方法并不確切地知道該如何對這一異常事件進(jìn)行處理屎勘,這時(shí)一個(gè)方法就應(yīng)該聲明拋棄異常,使得異常對象可以從調(diào)用棧向后傳播居扒,直到有合適的方法捕獲它為止概漱。
聲明拋棄異常是在一個(gè)方法聲明中的throws字句中指明的。例如:
public int read() throws IOException {
}
throws子句中同時(shí)可以指明多個(gè)異常喜喂,之間由逗號隔開瓤摧。例如:
public static void main(String[] args) throws IOException,IndexOutOfBoundsException {
}
2. 拋出異常
拋出異常就是產(chǎn)生異常對象的過程,首先要生成異常對象玉吁。異痴彰郑或者由虛擬機(jī)生成,或者由某些類的實(shí)例生成进副,也可以在程序中生成这揣。在方法中,拋出異常對象是通過throw
語句實(shí)現(xiàn)的。例如:
IOException e = new IOException();
throw e;
可以拋出的異常必須是Throwable或其子類的實(shí)例曾沈。
三. 自定義異常類
當(dāng)Java
內(nèi)置的異常都不能明確地說明異常情況的時(shí)候这嚣,開發(fā)人員往往需要定義一些異常類用于描述自身程序中的異常信息,以區(qū)分其他程序的異常信息塞俱。需要注意的是姐帚,唯一有用的就是類型名這個(gè)信息,所以不要在異常類的設(shè)計(jì)上花費(fèi)精力障涯。
實(shí)現(xiàn)自定義異常類的方法如下:
- (1) 類
java.lang.Throwable
是所有異常類的基類罐旗,它包括兩個(gè)子類:Exception
和Error
,Exception
類用于描述程序能夠捕獲的異常唯蝶,如ClassNotFoundException
九秀。Error
類用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問題,如虛擬機(jī)錯(cuò)誤粘我。 - (2) 自定義異常類必須是
Throwable
的直接或間接子類鼓蜒。自定義異常類可以繼承Throwable
類或者Exception
,而不要繼承Error
類征字,自定義異常類之間也可以有繼承關(guān)系都弹。 - (3) 需要為自定義異常類設(shè)計(jì)構(gòu)造方法,以方便構(gòu)造自定義異常對象匙姜。
一個(gè)方法所聲明拋棄的異常是作為這個(gè)方法與外界交互的一部分而存在的畅厢,所以方法的調(diào)用者必須了解這些異常,并確定如何正確地處理它們
1. 繼承Exception
public class MyFirstException extends Exception {
public MyFirstException() {
super();
}
public MyFirstException(String msg) {
super(msg);
}
public MyFirstException(String msg,Throwable cause) {
super(msg,cause);
}
public MyFirstException(Throwable cause) {
super(cause);
}
}
自定義異常類的主要作用是區(qū)分異常發(fā)生的位置氮昧,當(dāng)用戶遇到異常時(shí)框杜,根據(jù)異常名就可以知道哪里有異常,根據(jù)異常提示信息進(jìn)行修改
2. 繼承Throwable類
public class MySecondException extends Throwable {
public MySecondException() {
super();
}
public MySecondException(String msg) {
super(msg);
}
public MySecondException(String msg,Throwable cause) {
super(msg,cause);
}
public MySecondException(Throwable cause) {
super(cause);
}
}
當(dāng)一個(gè)try
塊后面跟著多個(gè)catch
塊時(shí)袖肥,如果發(fā)生的異常匹配第一個(gè)catch
塊的參數(shù)咪辱,便將異常處理權(quán)利交給第一個(gè)catch
塊;如果發(fā)生的異常與第一個(gè)catch
塊不匹配昭伸,便看是否與第二個(gè)catch
塊匹配梧乘,依次下去,如果到最后依然無法匹配該異常庐杨,便需要在方法聲明中添加一條throw
語句选调,將該異常拋出。
因此灵份,在有多個(gè)catch
塊仁堪,而且每次處理的異常類型具有繼承關(guān)系時(shí),應(yīng)該首先catch
子類異常填渠,再catch
父類異常弦聂。