初識異常(Exception)
-
比如我們在取數(shù)組里面的某個值得時候,經(jīng)常會出現(xiàn)定義的取值范圍超過了數(shù)組的大小,那么運行的時候JVM就會發(fā)出異常提示。
BoundException.png -
再比如我們要處理的數(shù)據(jù)超出了系統(tǒng)數(shù)據(jù)類型表示范圍時,由操作系統(tǒng)發(fā)出的Error提示。
MemoryError.png
發(fā)生異常的原因有很多,但是通常有以下幾大類:輸入了違法的數(shù)據(jù)、找不到要打開的文件、網(wǎng)絡(luò)通信中斷、JVM內(nèi)存溢出。
Java異常類層次
Java是通過Throwable類的所有子類來描述各種異常。所有異常的老祖宗都是Throwable。
Throwable
Throwable 類是所有錯誤或異常的超類。只有當(dāng)對象是此類(或其子類之一)的實例時,才能通過 Java 虛擬機(jī)或者 Java throw 語句拋出。類似地,只有此類或其子類之一才可以是 catch 中的參數(shù)類型。Throwable類有兩個重要的子類:Exception(異常)和 Error(錯誤)。
Error
Java程序通常不捕獲錯誤,出現(xiàn)錯誤一般都出現(xiàn)了比較嚴(yán)重的故障,此時程序已經(jīng)無法處理了,然后在控制臺通知你,我已經(jīng)歇菜了。大多數(shù)錯誤與程序的執(zhí)行操作無關(guān),而是程序運行時,JVM出了問題,如系統(tǒng)崩潰,虛擬機(jī)錯誤,內(nèi)存空間不足等。這些錯誤,僅靠程序本身無法恢復(fù)和和預(yù)防,遇到這樣的錯誤,建議讓程序終止。
Exception
Exception類表示程序可以處理的異常,是可以捕獲且可能恢復(fù)的。遇到這類異常,應(yīng)該盡可能處理異常,使程序恢復(fù)運行,而不應(yīng)該隨意終止異常。通常,Java的異常(包括Exception和Error)分為可查的異常(checked exceptions)和不可查的異常(unchecked exceptions)。
可查異常、不可查異常
可查異常(編譯器要求必須處置的異常):指程序在運行中,很容易出現(xiàn)的、情理可容的異常狀況。可查異常雖然是異常狀況,但在一定程度上它的發(fā)生是可以預(yù)計的,而且一旦發(fā)生這種異常狀況,就必須采取某種方式進(jìn)行處理。
除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于可查異常。這種異常的特點是Java編譯器會檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常,要么用try-catch語句捕獲它,要么用throws子句聲明拋出它,否則編譯不會通過。不可查異常(編譯器不要求強(qiáng)制處置的異常):包括運行時異常(RuntimeException與其子類)和錯誤(Error)。
運行時異常RuntimeException 是可能被程序員避免的異常。它是Exception的一個重要子類,是那些可能在 Java 虛擬機(jī)正常運行期間拋出的異常的超類。例如:ArithmeticException,一個整數(shù)“除以零”時會拋出此異常;ArrayStoreException,試圖將錯誤類型的對象存儲到一個對象數(shù)組時拋出此異常;IndexOutOfBoundsException,表示某排序索引(例如對數(shù)組、字符串排序)超出范圍時拋出此異常;NullPointerException,當(dāng)應(yīng)用程序試圖在需要對象的地方使用 null 時拋出該異常。這些異常都是不檢查異常,程序中可以選擇捕獲處理,也可以不處理。運行時異常的特點是Java編譯器不會檢查它,也就是說,當(dāng)程序中可能出現(xiàn)這類異常,即使沒有用try-catch語句捕獲它,也沒有用throws子句聲明拋出它,也會編譯通過。
異常方法
下面的列表是 Throwable 類的主要方法:
異常處理機(jī)制
在 Java 應(yīng)用程序中,異常處理機(jī)制為:拋出異常,捕捉異常。異常總是先被拋出,后被捕捉的。
-
拋出異常:當(dāng)一個方法出現(xiàn)錯誤引發(fā)異常時,方法創(chuàng)建異常對象并交付運行時系統(tǒng),異常對象中包含了異常類型和異常出現(xiàn)時的程序狀態(tài)等異常信息。運行時系統(tǒng)負(fù)責(zé)尋找處置異常的代碼并執(zhí)行。
注意:
對于運行時異常、錯誤或可查異常,Java技術(shù)所要求的異常處理方式有所不同。
① 由于運行時異常的不可查性,為了更合理、更容易地實現(xiàn)應(yīng)用程序,Java規(guī)定,運行時異常將由Java運行時系統(tǒng)自動拋出,允許應(yīng)用程序忽略運行時異常。對于方法運行中可能出現(xiàn)的Error,當(dāng)運行方法不欲捕捉時,Java允許該方法不做任何拋出聲明。因為,大多數(shù)Error異常屬于永遠(yuǎn)不能被允許發(fā)生的狀況,也屬于合理的應(yīng)用程序不該捕捉的異常。
② 對于所有的可查異常,Java規(guī)定:一個方法必須捕捉,或者聲明拋出方法之外。也就是說,當(dāng)一個方法選擇不捕捉可查異常時,它必須聲明將拋出異常。
代碼示例
① throws語句用在方法定義時聲明該方法要拋出的異常類型,如果拋出的是Exception異常類型,則該方法被聲明為拋出所有的異常。
② 當(dāng)方法拋出異常列表的異常時,方法將不對這些類型及其子類類型的異常作處理,而拋向調(diào)用該方法的方法,如果調(diào)用者不想處理該異常,可以繼續(xù)向上拋出,但最終要有能夠處理該異常的調(diào)用者。
③ throw總是出現(xiàn)在函數(shù)體中,用來拋出一個Throwable類型的異常。程序會在throw語句后立即終止,它后面的語句執(zhí)行不到。
public class ClassName
{
public void named(String string) throws RemoteException
{
// Method implementation
throw new RemoteException();
}
//Remainder of class definition
}
一個方法可以聲明拋出多個異常,多個異常之間用逗號隔開。
public class ClassName
{
public void withdraw(double amount) throws RemoteException, InsufficientFundsException
{
// Method implementation
}
//Remainder of class definition
}
-
捕獲異常:使用 try 和 catch 關(guān)鍵字可以捕獲異常。try/catch 代碼塊放在異常可能發(fā)生的地方。
語法
try
{
// 程序代碼
}catch(ExceptionName e)
{
//Catch 塊
}
當(dāng)try內(nèi)的監(jiān)控區(qū)域發(fā)生異常,就會匹配后面的catch塊。Java方法在運行過程中出現(xiàn)異常,則創(chuàng)建異常對象。將異常拋出監(jiān)控區(qū)域之外,由Java運行時系統(tǒng)試圖尋找匹配的catch子句以捕獲異常。若有匹配的catch子句,則運行其異常處理代碼,try-catch語句結(jié)束。
匹配的原則是:如果拋出的異常對象屬于catch塊的異常類,或者屬于該異常類的子類,則認(rèn)為生成的異常對象與catch塊捕獲的異常類型相匹配。
try/catch 實例:
public class Test{
public static void main(String args[]){
try{
int a[] = new int[2];
System.out.println("輸出數(shù)組 :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("拋出異常 :" + e);
}
}
}
多重捕獲塊:
try{
// 程序代碼
}catch(異常類型1 異常的變量名1){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}
如果監(jiān)控區(qū)域發(fā)生異常,異常被拋給第一個 catch 塊。如果拋出異常的數(shù)據(jù)類型與 ExceptionType1 匹配,它在這里就會被捕獲。如果不匹配,它會被傳遞給第二個 catch 塊。如此,直到異常被捕獲或者通過所有的 catch 塊。
多重捕獲塊實例:
public class TestException {
public static void main(String[] args) {
int[] intArray = new int[3];
try {
for (int i = 0; i <= intArray.length; i++) {
intArray[i] = i;
System.out.println("intArray[" + i + "] = " + intArray[i]);
System.out.println("intArray[" + i + "]模 " + (i - 2) + "的值: "
+ intArray[i] % (i - 2));
}
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("intArray數(shù)組下標(biāo)越界異常。");
} catch (ArithmeticException e) {
System.out.println("除數(shù)為0異常。");
}
System.out.println("程序正常結(jié)束。");
}
}
//intArray[0] = 0
//intArray[0]模 -2的值: 0
//intArray[1] = 1
//intArray[1]模 -1的值: 0
//intArray[2] = 2
//除數(shù)為0異常。
//程序正常結(jié)束。
注意:一旦某個catch捕獲到匹配的異常類型,將進(jìn)入異常處理代碼。一經(jīng)處理結(jié)束,就意味著整個try-catch語句結(jié)束。其他的catch子句不再有匹配和捕獲異常類型的機(jī)會。
finally關(guān)鍵字
① 無論是否發(fā)生異常,finally 代碼塊中的代碼總會被執(zhí)行。
② 在 finally 代碼塊中,可以運行清理類型等收尾善后性質(zhì)的語句。
③ finally 代碼塊出現(xiàn)在 catch 代碼塊最后。
④ finally中使用return是一種很不好的編程風(fēng)格,它會覆蓋掉所有的其它返回,并且吃掉catch中拋出的異常。
語法如下:
try{
// 程序代碼
}catch(異常類型1 異常的變量名1){
// 程序代碼
}catch(異常類型2 異常的變量名2){
// 程序代碼
}finally{
// 程序代碼
}
代碼實例:
public class ExcepTest{
public static void main(String args[]){
int a[] = new int[2];
try{
System.out.println("Access element three :" + a[3]);
}catch(ArrayIndexOutOfBoundsException e){
System.out.println("Exception thrown :" + e);
}
finally{
a[0] = 6;
System.out.println("First element value: " +a[0]);
System.out.println("The finally statement is executed");
}
}
}
//Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3
//First element value: 6
//The finally statement is executed
注意:當(dāng)在try塊或catch塊中遇到return語句時,finally語句塊將在方法返回之前被執(zhí)行。在finally語句塊中發(fā)生了異常,finally塊不會被執(zhí)行。
try-catch-finally執(zhí)行順序
1)當(dāng)try沒有捕獲到異常時:try語句塊中的語句逐一被執(zhí)行,程序?qū)⑻^catch語句塊,執(zhí)行finally語句塊和其后的語句;
2)當(dāng)try捕獲到異常,catch語句塊里沒有處理此異常的情況:當(dāng)try語句塊里的某條語句出現(xiàn)異常時,而沒有處理此異常的catch語句塊時,此異常將會拋給JVM處理,finally語句塊里的語句還是會被執(zhí)行,但finally語句塊后的語句不會被執(zhí)行;
3)當(dāng)try捕獲到異常,catch語句塊里有處理此異常的情況:在try語句塊中是按照順序來執(zhí)行的,當(dāng)執(zhí)行到某一條語句出現(xiàn)異常時,程序?qū)⑻絚atch語句塊,并與catch語句塊逐一匹配,找到與之對應(yīng)的處理程序,其他的catch語句塊將不會被執(zhí)行,而try語句塊中,出現(xiàn)異常之后的語句也不會被執(zhí)行,catch語句塊執(zhí)行完后,執(zhí)行finally語句塊里的語句,最后執(zhí)行finally語句塊后的語句;
自定義異常
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;
}
}
注意
子類重寫父類的方法的時候,如果父類沒有異常,那么子類也不允許在重寫的方法拋出異常有異常。也就是說父類沒有拋出異常,那么子類也不可以。
寫完嘍!ㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏ
知識重在總結(jié)和梳理,只有不斷地去學(xué)習(xí)并運用,才能化為自己的東西。當(dāng)你能為別人講明白的時候,說明自己已經(jīng)掌握了。
歡迎轉(zhuǎn)載,轉(zhuǎn)載請注明出處!
如果有錯誤的地方,或者有您的見解,還請不嗇賜教!
喜歡的話,麻煩點個贊!
本文轉(zhuǎn)載自:http://blog.csdn.net/hguisu/article/details/6155636
l