異常的定義:在《java編程思想》中這樣定義異常:阻止當前方法或作用域繼續執行的問題。
異常類的來源:一是java語言定義的一些基本異常;二是用戶自定義的一些異常,這些異常繼承Exception類或其子類。
異常對象的來源:一是java運行時環境拋出的異常;二是程序員自己手動拋出的異常,這種異常可以使程序員自己定義的,也可以是java語言定義的,通過throw關鍵字來拋出這種指定的異常,這種異常用來向調用者匯報異常的一些信息。
Java處理異常的5個關鍵字:try catch finally throw throws。在try語句中包含可能拋出異常的代碼,在catch中進行匹配并捕獲相應的異常對象,finally表示這段代碼必須執行,一般用于釋放一些物理資源,throw表示明確的拋出一個異常,在方法簽名處通過throws來表明可能拋出的各種異常。
在java程序執行try塊 catch塊時遇到了return或throw語句,這兩條并不是立即執行,首先看看是否含有finally部分,如果有,先執行finally部分,再跳回到try或catch塊里的return或throw語句,如果沒有finally部分,程序立即執行try或catch塊里的return或throw語句。若finally里面也有return或throw語句,系統將不會再跳到try或catch塊里面。
一般結構:
try{
程序代碼
}catch(異常類型1 異常的變量名1){
程序代碼
}catch(異常類型2 異常的變量名2){
程序代碼
}finally{
程序代碼
}
catch可以有多個,按異常類從小到大進行排列,try語句中拋出的異常對象只要在catch中有一個匹配成功,就不再進行往下的匹配。Catch括號中的異常類可以是java語言定義的類也可以是自己定義的類,異常變量名表示拋出異常類對象的引用,可以在catch代碼塊中直接使用這個變量名,通過這個引用(變量名)的方法來獲得異常對象的詳細信息。
常見異常繼承關系:
Exception表示程序本身可以處理的異常
Error一般是指虛擬機相關的問題,如系統失敗,動態鏈接失敗等,這種錯誤無法恢復或捕獲,程序將中斷。所以不應該捕獲這種error錯誤。
RunttimeExceptionJava 虛擬機正常運行期間拋出的異常的超類。Java編譯器不去檢查它,也就是說,當程序中可能出現這類異常時,即使沒有用try...catch語句捕獲它,也沒有用throws字句聲明拋出它,還是會編譯通過,這種異常可以通過改進代碼實現來避免。
處理異常一般用兩種方式:
第一:在catch語句中處理
第二:對于處理不了的異常用throw拋出指定異常,并在方法簽名處通過throws拋出,讓上一級的調用者來處理,如果main方法也不知道如何處理,也使用throws方法拋出異常,該異常將交給虛擬機來處理。Java虛擬機會從出現異常的方法代碼 塊中往上找,直到找到處理該異常的代碼塊為止。然后將異常交給相應的catch語句處理。如果Java虛擬機追溯到方法調用棧底部main()方法時, 如果仍然沒有找到處理異常的代碼塊,將按照下面的步驟處理:
(1) 調用異常的對象的printStackTrace()方法,打印方法調用棧的異常信息。
(2) 如果出現異常的線程為主線程,則整個程序運行終止;如果非主線程,則終止該線程,其他線程繼續運行。
通過分析思考可以看出,越早處理異常消耗的資源和時間越小,產生影響的范圍也越小。因此,不要把自己能處理的異常也拋給調用者。
并且注意try語句不能單獨存在,可以和catch、finally組成 try...catch...finally、try...catch、try...finally三種結構,catch語句可以有一個或多 個,finally語句多一個,try、catch、finally這三個關鍵字均不能單獨使用。throw語句后不允許有緊跟其他語句,因為這些沒有機會執行。
一個方法可能拋出異常的標志是:
1 在方法簽名處有throws語句
2 在方法中含有throw語句
自定義異常類
創建Exception或者RuntimeException的子類即可得到一個自定義的異常類。例如:
public class MyException extends Exception{
public MyException(){}
public MyException(String smg){
super(smg);
}
}
Exception類可以分為兩種:運行時異常和受檢查異常。
1、運行時異常
RuntimeException 類及其子類都被稱為運行時異常,這種異常的特點是Java編譯器不去檢查它,也就是說,當程序中可能出現這類異常時,即使沒有用try...catch語 句捕獲它,也沒有用throws字句聲明拋出它,還是會編譯通過。例如,當除數為零時,就會拋出 java.lang.ArithmeticException異常。
2、受檢查異常
意味著程序出現了bug,如數組越界,0被除等。除了RuntimeException類及其子類外,其他的Exception類及其子類都屬于受檢查異常,這種異常的特點是要么用try...catch捕獲處理,要么用throws語句聲明拋出,否則編譯不會通過。
3、兩者的區別
運行時異常表示無法讓程序恢復運行的異常,導致這種異常的原因通常是由于執行了錯誤的操作。一旦出現錯誤,建議讓程序終止。
受檢查異常表示程序可以處理的異常。如果拋出異常的方法本身不處理或者不能處理它,那么方法的調用者就必須去處理該異常,否則調用會出錯,連編譯也無法通過。當然,這兩種異常都是可以通過程序來捕獲并處理的。
4、運行時錯誤
一般很少見,也很難通過程序解決。它可能源于程序的bug,但一般更可能源于環境問題,如內存耗盡。錯誤在程序中無須處理,而有運行環境處理。Error類及其子類表示運行時錯誤,通常是由Java虛擬機拋出的。程序本身無法修復這些錯誤.一般不去擴展Error類來創建用戶自定義的錯誤類。而RuntimeException類表示程序代碼中的錯誤,是可擴展的,用戶可以創建特定運行時異常類。
Error(運行時錯誤)和運行時異常的相同之處是:Java編譯器都不去檢查它們,當程序運行時出現它們,都會終止運行。
5、佳解決方案
對于運行時異常,我們不要用try...catch來捕獲處理,而是在程序開發調試階段,盡量去避免這種異常,一旦發現該異常,正確的做法就會改進程序設計 的代碼和實現方式,修改程序中的錯誤,從而避免這種異常。捕獲并處理運行時異常是好的解決辦法,因為可以通過改進代碼實現來避免該種異常的發生。
對于受檢查異常,沒說的,老老實實去按照異常處理的方法去處理,要么用try...catch捕獲并解決,要么用throws拋出!對于Error(運行時錯誤),不需要在程序中做任何處理,出現問題后,應該在程序在外的地方找問題,然后解決。
程序發生異常情況時,首先,同其它java對象的創建一樣,在堆中new出一個異常對象。然后,當前的執行路徑被終止,如果出現異常的線程為主線程,則整個程序運行終止;如果非主線程,則終止該線程,其他線程繼續運行。同時從當前環境中拋出該異常對象的引用。此時,異常處理機制接管程序,并尋找一個合適的地方繼續執行程序,即異常處理程序,它的任務是將程序從錯誤中恢復。
在new出異常對象的時候,隨之進行的是存儲空間的分配和構造器的調用。所有的標準異常類都有兩個構造器:一個是默認的構造器;另一個是接受字符串作為參數,以便將相關信息放入異常對象的構造器。因為異常對象是在堆中new出的,所有垃圾回收器會自動將它們清理到。
對于錯誤的信息可以保存在異常對象的內部或用異常對象的類名來進行暗示。
有時可能用不到標示符,因為異常的類型已經足夠暗示異常的信息,但標示符不能省略。
我們平時所關心的異常的基類通常是Exception異常。
拋出異常時,異常處理系統會按順序查找“近”的catch,一旦找到匹配的處理catch,就不再繼續匹配了。對于類型的匹配,派生類的對象也可以匹配其基類的處理程序。
異常處理的優點之一就是是得我們可以在某處集中精力處理要解決的問題,而在另一處處理編寫的這段代碼中產生的錯誤。