目錄:
一、 異常繼承體系
二、 發(fā)生異常到時候般堆,程序的執(zhí)行特征:
三在孝、 異常與錯誤的區(qū)別
四、 拋出異常 throw
五淮摔、 聲明異常 throws
六私沮、 捕獲異常 try…catch…finally
七、 try…catch…finally 異常處理的組合方式
八和橙、 異常在方法重寫中細(xì)節(jié)
九仔燕、 Throwable 類中的常用方法
十、 try和finally中都有return語句魔招,執(zhí)行哪一個 return晰搀?
十一、 自定義異常
一办斑、 異常繼承體系
- 異常是程序運行過程中出現(xiàn)的錯誤外恕。Java 把異常當(dāng)作對象來處理,把異常信息封裝成了一個類乡翅,并定義一個基類 java.lang.Throwable 作為所有異常的超類鳞疲。
-
Throwable
: 它是所有錯誤與異常的超類(祖宗類)
,有兩個子類Error 和Exception-
Error
: 錯誤。程序無法處理的錯誤蠕蚜,比如OutOfMemoryError建丧、ThreadDeath等。這些異常發(fā)生時波势,Java虛擬機(JVM)一般會選擇線程終止翎朱。 -
Exception
: 異常。程序本身可以處理的異常尺铣,程序中應(yīng)當(dāng)盡可能去處理這些異常拴曲。-
RuntimeException
: 運行期異常, JAVA程序運行過程中出現(xiàn)的問題 -
CheckableException
: 編譯時異常或者可檢查異常, 是除了RuntimeExecption(及其子類)之外的所有 Exception
-
-
- 運行時期異常:
- 方法中拋出運行時期異常,方法定義中無需throws聲明,調(diào)用者也無需處理此異常
- 運行時期異常一旦發(fā)生,需要程序人員修改源代碼.
- 編譯時異常: 必須在編譯前處理,否則無法通過編譯
二凛忿、 發(fā)生異常到時候澈灼,程序的執(zhí)行特征:
- 我們的代碼,從發(fā)生異常的地方店溢,開始被一分為二
- 在異常發(fā)生之前的代碼叁熔,都可以正常運行,之后的代碼不會執(zhí)行
- 當(dāng)異常發(fā)生的時候床牧,這個異常被 jvm 所捕獲荣回,并將這個異常的所有相關(guān)信息,創(chuàng)建為一個異常對象戈咳,然后將該異常對象的信息輸出到控制臺(執(zhí)行的是虛擬機默認(rèn)的異常處理代碼)
- 終止當(dāng)前程序
三心软、 異常與錯誤的區(qū)別
-
異常
:指程序在編譯壕吹、運行期間發(fā)生了某種異常(XxxException),我們可以對異常進(jìn)行具體的處理删铃。若不處理異常耳贬,程序?qū)Y(jié)束運行。
-
錯誤
:指程序在運行期間發(fā)生了某種錯誤(XxxError)猎唁,Error 錯誤通常沒有具體的處理方式咒劲,程序?qū)Y(jié)束運行。Error錯誤的發(fā)生往往都是系統(tǒng)級別的問題诫隅,都是jvm所在系統(tǒng)發(fā)生并反饋給jvm的腐魂。我們無法針對處理,只能修正代碼阎肝。
四、 拋出異常 throw
- 在 java 中肮街,提供了一個
throw
關(guān)鍵字风题,它用來拋出一個指定的(Throwable類型)異常對象. - 一般會用于程序出現(xiàn)某種邏輯時,程序員主動拋出某種特定類型的異常
- 具體步驟:
- 創(chuàng)建一個異常對象, 封裝一些提示信息(信息可以自己編寫).
- 通過關(guān)鍵字 throw, 將這個異常對象告知給調(diào)用者.
- throw 用在方法內(nèi)嫉父,用來拋出一個異常對象沛硅,將這個異常對象傳遞到調(diào)用者處,并結(jié)束當(dāng)前方法的執(zhí)行绕辖。
-
使用格式:
throw new 異常類名(參數(shù));
throw new NullPointerException("要訪問的arr數(shù)組不存在");
throw new ArrayIndexOutOfBoundsException("該索引在數(shù)組中不存在摇肌,已超出范圍");
//具體范例:
public static void main(String[] args) {
String s = "abc";
if(s.equals("abc")) {
throw new NumberFormatException();
} else {
System.out.println(s);
}
//function();
}
-
注意事項:
- 如果拋出的異常對象屬于可檢查的異常,必須在該方法頭部仪际,聲明拋出此異常, 即:
throws 要拋出的異常類型
- 其次围小,對于拋出可檢查的異常,還必須與方法的異常列表中的異常兼容
-
如果父類方法聲明了異常列表:
- 子類可以不聲明異常列表
- 子類方法有自己異常列表時树碱,必須保證肯适,子類的異常列表所包含的異常類型,與父類中所包含的異常類型兼容
- 如果拋出的異常對象屬于可檢查的異常,必須在該方法頭部仪际,聲明拋出此異常, 即:
五成榜、 聲明異常 throws
- 聲明:將問題標(biāo)識出來框舔,報告給調(diào)用者
-
throws
是方法可能拋出異常的聲明, 如果定義功能時有問題發(fā)生需要報告給調(diào)用者∈昊椋可以通過在方法上使用 throws 關(guān)鍵字進(jìn)行聲明刘绣。
- 對于聲明了會拋出可檢查異常的方法, 就意味著這個方法會產(chǎn)生可檢查異常,所以挣输,一旦調(diào)用該方法就必須對該方法做異常處理
- throws 用于進(jìn)行異常類的聲明纬凤,若該方法可能有多種異常情況產(chǎn)生,那么在 throws 后面可以寫多個異常類撩嚼,用逗號隔開移斩。
-
聲明異常格式:
修飾符 返回值類型 方法名(參數(shù)) throws <異常列表> { }
public static void function() throws NumberFormatException{
String s = "abc";
System.out.println(Double.parseDouble(s));
}
public static void main(String[] args) {
try {
function();
} catch (NumberFormatException e) {
System.err.println("非數(shù)據(jù)類型不能轉(zhuǎn)換肚医。");
}
}
六、 捕獲異常 try…catch…finally
1. 概述
- 捕獲:Java中對異常有針對性的語句進(jìn)行捕獲向瓷,可以對出現(xiàn)的異常進(jìn)行指定方式的處理
- 捕獲異常格式:
try {
//需要被檢測的語句肠套。
}
catch(異常類 e) { //try中拋出的是什么異常,在括號中就定義什么異常類型猖任。
//異常的處理語句你稚。
}
finally {
//一定會被執(zhí)行的語句。
}
//try:該代碼塊中編寫可能產(chǎn)生異常的代碼朱躺。
//catch:用來進(jìn)行某種異常的捕獲刁赖,實現(xiàn)對捕獲到的異常進(jìn)行處理。
//finally:有一些特定的代碼無論異常是否發(fā)生长搀,都需要執(zhí)行宇弛。另外,因為異常會引發(fā)程序跳轉(zhuǎn)源请,導(dǎo)致有些語句執(zhí)行不到枪芒。而finally就是解決這個問題的,在finally代碼塊中存放的代碼都是一定會被執(zhí)行的谁尸。
- 某個函數(shù)或某段程序塊不管會不會舅踪,有沒可能拋出異常,都可以加
try{...}catch{...}
去捕捉它良蛮。
2. 異常處理流程:
- 首先抽碌,當(dāng)異常在 try 代碼塊中發(fā)生的時候,虛擬機首先捕獲這個異常决瞳,創(chuàng)建一個異常對象(包含本次異常的所有詳細(xì)信息)
- 虛擬機會把這個異常货徙,拋出給catch代碼塊(類似于方法調(diào)用,虛擬機會調(diào)用catch代碼塊中皮胡,處理異常的代碼)
- 執(zhí)行catch代碼塊破婆,中的處理異常的代碼
- 沒有終止我們應(yīng)用程序,而是從catch語句之后的代碼開始胸囱,繼續(xù)執(zhí)行我們的應(yīng)用程序
在try語句塊中祷舀,一旦發(fā)生異常,我們的代碼仍然被一分為二
- 在異常發(fā)生之前帶代碼都正常運行
- 在異常發(fā)生之后的代碼烹笔,不會執(zhí)行裳扯,而是直接跳轉(zhuǎn)到我們自己處理異常的catch代碼塊中
七、 try…catch…finally 異常處理的組合方式
- try catch finally組合: 檢測異常谤职,并傳遞給 catch 處理饰豺,并在 finally 中進(jìn)行資源釋放。
即使在finally代碼塊執(zhí)行了return語句允蜈,finally代碼塊中的代碼冤吨,仍然會執(zhí)行
特殊情況: 走到finally之前 JVM 退出了,就不會執(zhí)行finally了
finally在開發(fā)中的應(yīng)用:用于釋放資源
- try catch組合 : 對代碼進(jìn)行異常檢測蒿柳,并對檢測的異常傳遞給catch處理。對異常進(jìn)行捕獲處理
- 多個try catch組合 當(dāng)可能有多種類型的異常發(fā)生的時候漩蟆,我把可能產(chǎn)生某異常類型的代碼分開垒探,分別放在不同的try-catch代碼塊中
- 執(zhí)行特征是:
- 每個try-catch中是否拋出異常,相互獨立的
- 在實際執(zhí)行的時候怠李,每一個try-catch代碼塊可能都產(chǎn)生異常圾叼。
- 實際開發(fā)的時候,一般來講:
- 效率角度捺癞,try 塊中方的代碼越少越好
- 開發(fā)的時候夷蚊,會將相關(guān)的異常,放在同一個 try 塊
- 相關(guān)異常: 一個連續(xù)的流程中髓介,可能發(fā)生的一系列異常
- 所以一系列相關(guān)的流程中惕鼓,一旦前一步出現(xiàn)了異常,就會導(dǎo)致唐础,即使后面的流程正常執(zhí)行箱歧,其實也已經(jīng)沒有意義了
- 一個try 多個catch組合 : 對代碼進(jìn)行異常檢測,并對檢測的異常傳遞給catch處理彻犁。對每種異常信息進(jìn)行不同的捕獲處理叫胁。
這種異常處理方式凰慈,要求多個catch中的異常不能相同汞幢,
若catch中的多個異常之間有子父類異常的關(guān)系,那么先寫子類異常類型微谓,再寫父類異常類型
當(dāng)發(fā)生異常的時候森篷, 最多執(zhí)行一個catch分支的代碼
public class Demo {
public static void main(String[] args) {
try{
int i = 10;
//可能發(fā)生異常的語句
int j = i / 0;
System.out.println("try after exception");
//空指針異常
int[] a = null;
System.out.println(a[0]);
//數(shù)組越界異常
int[] b = {1, 2, 3};
System.out.println(b[3]);
}catch (ArithmeticException e) {
System.out.println("發(fā)生了除0異常");
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) { //一個catch分支處理多種類型的異常
System.out.println("發(fā)生了數(shù)組異常");
}
}
}
- try finally 組合: 對代碼進(jìn)行異常檢測,檢測到異常后因為沒有catch豺型,所以一樣會被默認(rèn) jvm 拋出仲智。異常是沒有捕獲處理的。但是功能所開啟資源需要進(jìn)行關(guān)閉姻氨,所以 finally 只為關(guān)閉資源
八钓辆、 異常在方法重寫中細(xì)節(jié)
- 子類覆蓋父類方法時,如果父類的方法聲明異常肴焊,子類只能聲明父類異常或者該異常的子類前联,或者不聲明。
class Fu {
public void method () throws RuntimeException {
}
}
class Zi extends Fu {
public void method() throws RuntimeException { } //拋出父類一樣的異常
//public void method() throws NullPointerException{ } //拋出父類子異常
}
- 當(dāng)父類方法聲明多個異常時娶眷,子類覆蓋時只能聲明多個異常的子集似嗤。
class Fu {
public void method () throws NullPointerException, ClassCastException{
}
}
class Zi extends Fu {
public void method()throws NullPointerException, ClassCastException { }
public void method() throws NullPointerException{ } //拋出父類異常中的一部分
public void method() throws ClassCastException { } //拋出父類異常中的一部分
}
- 當(dāng)被覆蓋的方法沒有異常聲明時,子類覆蓋時無法聲明異常的届宠。
九烁落、 Throwable類中的常用方法
-
getCause()
:返回拋出異常的原因乘粒,即異常提示信息。如果 cause 不存在或未知伤塌,則返回 null灯萍。 -
getMessage()
:返回異常的消息信息,即該異常的名稱與詳細(xì)信息字符串 -
printStackTrace()
:在控制臺輸出該異常的名稱與詳細(xì)信息字符串寸谜、異常出現(xiàn)的代碼位置
十竟稳、 try和finally中都有return語句,執(zhí)行哪一個return熊痴?
- 首先要確定的一點是他爸,不管有木有出現(xiàn)異常,finally塊中代碼都會執(zhí)行
- 當(dāng)try和catch中有return時果善,finally仍然會執(zhí)行诊笤;
- finally是在return后面的表達(dá)式運算后執(zhí)行的(此時并沒有返回運算后的值,而是先把要返回的值保存起來巾陕,不管finally中的代碼怎么樣讨跟,返回的值都不會改變,任然是之前保存的值)鄙煤,所以函數(shù)返回值是在finally執(zhí)行前確定的晾匠;
- finally中最好不要包含return,否則程序會提前退出梯刚,返回值不是try或catch中保存的返回值凉馆。
問:如果try和finally語句里面都有return,會執(zhí)行哪一個呢亡资?
首先澜共,在程序沒有異常的情況下,首先執(zhí)行到try里面的語句锥腻,但是只執(zhí)行到了return里面的****expression嗦董,expression首先存放在操作數(shù)棧頂,然后復(fù)制到局部變量區(qū)瘦黑,并沒有執(zhí)行返回語句return(執(zhí)行返回語句通常意味著程序執(zhí)行結(jié)束)京革。然后執(zhí)行finally,當(dāng)執(zhí)行到finally里面的return時候幸斥,會將return語句執(zhí)行完整匹摇,此時程序已經(jīng)有了返回值,因為睡毒,執(zhí)行結(jié)束来惧。
- 總結(jié):執(zhí)行try塊,執(zhí)行到return語句時演顾,先執(zhí)行return的語句供搀,但是不返回到main 方法隅居,接下來執(zhí)行finally塊,遇到finally塊中的return語句葛虐,執(zhí)行,并將值返回到main方法胎源,這里就不會再回去返回try塊中計算得到的值
十一、 自定義異常
1. 概述
- 如果Java沒有提供你需要的異常屿脐,則可以自定義異常類涕蚤。
- 編譯時異常繼承 Exception,運行時異常繼承 RuntimeException
- 格式:
Class 異常名 extends Exception{ //或繼承RuntimeException
public 異常名(){
}
public 異常名(String s){
super(s);
}
}
2. 示例
需求描述:
定義Person類的诵,包含name與age兩個成員變量万栅。
在Person類的有參數(shù)構(gòu)造方法中,進(jìn)行年齡范圍的判斷西疤,若年齡為負(fù)數(shù)或大于200歲烦粒,則拋出NoAgeException異常,異常提示信息“年齡數(shù)值非法”代赁。
要求:在測試類中扰她,調(diào)用有參數(shù)構(gòu)造方法,完成Person對象創(chuàng)建芭碍,并進(jìn)行異常的處理徒役。
//自定義異常類
class NoAgeException extends Exception{
NoAgeException() {
super();
}
NoAgeException(String message) {
super(message);
}
}
//Person類
class Person{
private String name;
private int age;
Person(String name,int age) throws NoAgeException {
//加入邏輯判斷
if(age<0 || age>200) {
throw new NoAgeException(age+",年齡數(shù)值非法");
}
this.name = name;
this.age = age;
}
//定義Person對象對應(yīng)的字符串表現(xiàn)形式。覆蓋Object中的toString方法窖壕。
public String toString() {
return "Person[name="+name+",age="+age+"]";
}
}
//測試類
class ExceptionDemo{
public static void main(String[] args) {
try {
Person p = new Person("xiaoming",20);
System.out.println(p);
}
catch (NoAgeException ex){
System.out.println("年齡異常啦");
}
System.out.println("over");
}
}
總結(jié)一下忧勿,構(gòu)造函數(shù)到底拋出這個NoAgeException是繼承Exception呢?還是繼承RuntimeException呢艇拍?
繼承Exception狐蜕,必須要throws聲明宠纯,一聲明就告知調(diào)用者進(jìn)行捕獲卸夕,一旦問題處理了調(diào)用者的程序會繼續(xù)執(zhí)行。
繼承RuntimeExcpetion,不需要throws聲明的婆瓜,這時調(diào)用是不需要編寫捕獲代碼的快集,因為調(diào)用根本就不知道有問題。一旦發(fā)生NoAgeException廉白,調(diào)用者程序會停掉个初,并有jvm將信息顯示到屏幕,讓調(diào)用者看到問題猴蹂,修正代碼院溺。