Java异常详解及自定义异常
我已經(jīng)不用 try catch 處理異常了!太煩人了_51CTO博客_try catch處理什么異常
一、異常的概念
1.定義(什么是異常?)
異常是例外,是一個(gè)程序在執(zhí)行期間發(fā)生的事件,它中斷正在執(zhí)行程序的正常指令流。軟件開(kāi)發(fā)過(guò)程中,很多情況都會(huì)導(dǎo)致異常的產(chǎn)生,例如對(duì)負(fù)數(shù)開(kāi)平方根、對(duì)字符串做算術(shù)運(yùn)算、操作數(shù)超出范圍、數(shù)組下標(biāo)越界等。
2.異常簡(jiǎn)單例子
(1)除數(shù)為零的例子
/*** @Author: qp* @Time: 2021/8/24 21:11* @Description*/ public class Example6_1 {public static void main(String[] args){int a= 0;System.out.println(5/a);} }輸出結(jié)果:由于除數(shù)不能為0,所以程序運(yùn)行時(shí)出現(xiàn)了除以0溢出的異常事件。
Exception in thread "main" java.lang.ArithmeticException: / by zeroat com.chapter6.Example6_1.main(Example6_1.java:11)(2)類(lèi)型轉(zhuǎn)換錯(cuò)誤
/*** @Author: qp* @Time: 2021/8/24 21:14* @Description*/ public class Example6_2 {public static void main(String[] args){String str = "jack";System.out.println(str+"年齡是:");String s = "20L";int age = Integer.parseInt(s);System.out.println(age);} }輸出結(jié)果為:報(bào)出NumberFormatException(數(shù)字格式異常),程序提示了消息,可見(jiàn)提示的消息代碼正常執(zhí)行,而變量age沒(méi)有執(zhí)行,故s轉(zhuǎn)換為age的時(shí)候程序異常了。
jack年齡是: Exception in thread "main" java.lang.NumberFormatException: For input string: "20L"at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)at java.lang.Integer.parseInt(Integer.java:580)at java.lang.Integer.parseInt(Integer.java:615)at com.chapter6.Example6_2.main(Example6_2.java:13)上面的兩個(gè)程序拋出了兩種異常,這兩種異常是一個(gè)個(gè)的異常對(duì)象,異常對(duì)象的產(chǎn)生取決于產(chǎn)生異常的類(lèi)型。此時(shí)的異常可以概括為:
異常是程序由于各種原因?qū)е聼o(wú)法正常運(yùn)行的一個(gè)事件,這個(gè)事件是由一個(gè)異常對(duì)象來(lái)代表的,這個(gè)對(duì)象的產(chǎn)生取決于產(chǎn)生異常的類(lèi)型,可能由應(yīng)用程序本身產(chǎn)生,也可能由Java虛擬機(jī)產(chǎn)生。
二、異常類(lèi)的層次
checked Exception和unchecked Exception的區(qū)別:
要想明白Java中checked Exception和unchecked Exception的區(qū)別,我們首先來(lái)看一下Java的異常層次結(jié)構(gòu)。
?這是一個(gè)簡(jiǎn)化的Java異常層次結(jié)構(gòu)示意圖,需要注意的是所有的類(lèi)都是從Throwable繼承而來(lái),下一層則分為兩個(gè)結(jié)構(gòu),Error和Exception。其中Error類(lèi)層次描述了Java運(yùn)行時(shí)系統(tǒng)的內(nèi)部錯(cuò)誤和資源耗盡錯(cuò)誤,這種錯(cuò)誤除了簡(jiǎn)單的報(bào)告給用戶,并盡力阻止程序安全終止之外,一般也米有別的解決辦法了。
(二)unchecked異常和checked異常的區(qū)別
??有了上面的認(rèn)識(shí)之后,我們?cè)賮?lái)看什么是checked異常,什么是unchecked的異常。其實(shí),Java語(yǔ)言規(guī)范對(duì)這兩個(gè)定義十分簡(jiǎn)單,將派生于Error或者RuntimeException的異常稱為unchecked異常,所有其他的異常成為checked異常。
1.異常類(lèi)的層次
2.異常事件類(lèi)型
異常類(lèi)都是內(nèi)置類(lèi)Throwable的子類(lèi)。Throwable類(lèi)有兩個(gè)子類(lèi):Error(錯(cuò)誤)和Exception(異常)
- Error(錯(cuò)誤):通常是災(zāi)難性的致命錯(cuò)誤,不是程序(程序猿)可以控制的,如內(nèi)存耗盡、JVM系統(tǒng)錯(cuò)誤、堆棧溢出等。應(yīng)用程序不應(yīng)該去處理此類(lèi)錯(cuò)誤,且程序員不應(yīng)該實(shí)現(xiàn)任何Error類(lèi)的子類(lèi)。
- Exception(異常):用戶可能捕獲的異常情況,可以使用針對(duì)性的代碼進(jìn)行處理,如:空指針異常、網(wǎng)絡(luò)連接中斷、數(shù)組下標(biāo)越界等。
3.Exception(異常)分類(lèi)
Exception(異常)又分為兩類(lèi):運(yùn)行時(shí)異常和編譯時(shí)異常。
(1)運(yùn)行時(shí)異常
RuntimeException為Java虛擬機(jī)在運(yùn)行時(shí)自動(dòng)生成的異常,如被零除和非法索引、操作數(shù)超過(guò)數(shù)組范圍、打開(kāi)文件不存在等。此類(lèi)異常的出現(xiàn)絕大數(shù)情況是代碼本身有問(wèn)題應(yīng)該從邏輯上去解決并改進(jìn)代碼。
RuntimeException類(lèi)及其子類(lèi)稱為非檢查型異常,Java編譯器會(huì)自動(dòng)按照異常產(chǎn)生的原因引發(fā)相應(yīng)類(lèi)型的異常,程序中可以選擇捕獲處理也可以不處理,雖然Java編譯器不會(huì)檢查運(yùn)行時(shí)異常,但是也可以去進(jìn)行捕獲和拋出處理。RuntimeException類(lèi)和子類(lèi)以及Error類(lèi)都是非受檢異常。
(2)編譯時(shí)異常
Exception中除RuntimeException及其子類(lèi)之外的異常,該異常必須手動(dòng)在代碼中添加捕獲語(yǔ)句或一直向上拋出,來(lái)處理該異常。編譯時(shí)異常也稱為受檢異常,一般不進(jìn)行自定義檢查異常。
4.常見(jiàn)的異常類(lèi)
| ClassCastException | 類(lèi)型轉(zhuǎn)換異常 |
| ArrayIndexOutOfBoundsException | 數(shù)組越界異常 |
| NegativeArraySizeException | 指定數(shù)組維數(shù)為負(fù)值異常 |
| ArithmeticException | 算數(shù)異常 |
| InternalException | Java系統(tǒng)內(nèi)部異常 |
| NullPointerException | 空指針異常 |
| IllegalAccessException | 類(lèi)定義不明確所產(chǎn)生的異常 |
| IOException | 一般情況下不能完成I/O操作產(chǎn)生的異常 |
| EOFException | 打開(kāi)文件沒(méi)有數(shù)據(jù)可以讀取的異常 |
| FileNotFoundException | 在文件系統(tǒng)中找不到文件路徑或文件名稱時(shí)的異常 |
| ClassNotFoundException | 找不到類(lèi)或接口所產(chǎn)生的異常 |
| CloneNotSupportedException | 使用對(duì)象的clone方法但無(wú)法執(zhí)行Cloneable所產(chǎn)生的異常 |
5.異常類(lèi)的常用方法
- getMessage():返回Throwable對(duì)象的詳細(xì)信息,如果該對(duì)象沒(méi)有詳細(xì)信息則返回null(常用打印錯(cuò)誤信息)
- getLocalizedMessage() :返回Throwable的本地化描述,子類(lèi)可能會(huì)覆蓋該方法以便產(chǎn)生一個(gè)特定于本地的消息,對(duì)于未覆蓋該方法的子類(lèi),默認(rèn)返回調(diào)用getMessage()的結(jié)果
- printStackTrace():將Throwable和它的跟蹤情況打印到標(biāo)準(zhǔn)錯(cuò)誤流(常用打印詳細(xì)追蹤錯(cuò)誤信息)
- toString():返回Throwable對(duì)象的類(lèi)型與性質(zhì)
三、Java異常處理過(guò)程
1.什么叫異常處理機(jī)制?
前面定義過(guò):異常是程序由于各種原因?qū)е聼o(wú)法正常運(yùn)行的一個(gè)事件,這個(gè)事件是由一個(gè)異常對(duì)象來(lái)代表的,這個(gè)對(duì)象的產(chǎn)生取決于產(chǎn)生異常的類(lèi)型,可能由應(yīng)用程序本身產(chǎn)生,也可能由Java虛擬機(jī)產(chǎn)生。異常事件是 Throwable 類(lèi)或其子類(lèi)的實(shí)例(異常對(duì)象),異常處理機(jī)制就是當(dāng)一個(gè)方法出現(xiàn)異常后便拋出一個(gè)異常對(duì)象,該對(duì)象中包含有異常信息,調(diào)用這個(gè)對(duì)象的方法可以捕獲到這個(gè)異常并可以對(duì)其進(jìn)行處理,異常處理機(jī)制并不能真正的修復(fù)程序的bug,只能說(shuō)是防止程序崩潰,要修復(fù)程序的bug時(shí)需要我們?cè)赾atch語(yǔ)句中對(duì)異常進(jìn)行一些處理。
- 定義:Java是采用面向?qū)ο蟮姆绞絹?lái)處理異常的。處理過(guò)程:
(1)拋出異常:在執(zhí)行一個(gè)方法時(shí),如果發(fā)生異常,則這個(gè)方法生成代表該異常的一個(gè)對(duì)象,停止當(dāng)前執(zhí)行路徑,并把異常對(duì)象提交給運(yùn)行時(shí)系統(tǒng)(JRE)。
(2)捕獲異常:JRE得到該異常后,尋找相應(yīng)的代碼來(lái)處理該異常。JRE在方法的調(diào)用棧中查找,從生成異常的方法開(kāi)始回溯,直到找到相應(yīng)的異常處理代碼為止。 - 限制:Exception 中除 RuntimeException 及其子類(lèi)之外的異常一般需要進(jìn)行異常處理
2.Java異常關(guān)鍵字
Java 的異常處理是通過(guò) 5 個(gè)關(guān)鍵詞來(lái)實(shí)現(xiàn)的:try、catch、throw、throws 和 finally
? try – 用于監(jiān)聽(tīng)。將要被監(jiān)聽(tīng)的代碼(可能拋出異常的代碼)放在try語(yǔ)句塊之內(nèi),當(dāng)try語(yǔ)句塊內(nèi)發(fā)生異常時(shí),異常就被拋出。
? catch – 用于捕獲異常。catch用來(lái)捕獲try語(yǔ)句塊中發(fā)生的異常。
? finally – finally語(yǔ)句塊總是會(huì)被執(zhí)行。
? throw – 用于拋出異常。
? throws – 用在方法簽名中,用于聲明該方法可能拋出的異常。
3.異常處理機(jī)制類(lèi)型
- 在Java應(yīng)用中,異常的處理機(jī)制分為聲明異常,拋出異常和捕獲異常。
- 異常處理機(jī)制類(lèi)型與異常關(guān)鍵字的對(duì)應(yīng)關(guān)系
4.Java異常處理過(guò)程——捕獲異常catch
(1)定義
異常對(duì)象被系統(tǒng)沿著方法的調(diào)用棧逐層回溯,交給能夠匹配這種異常對(duì)象的異常引用,接著對(duì)異常對(duì)象進(jìn)行處理,這一過(guò)程就是捕獲(catch)異常。
(2)結(jié)構(gòu)語(yǔ)法
try {// 程序代碼塊}catch (ExceptionType1 e){// 對(duì)ExceptionType1的處理}catch (ExceptionType2 e){// 對(duì)ExceptionType2的處理}...final{// 程序代碼塊 }try語(yǔ)句中存放的是可能發(fā)生異常的語(yǔ)句。當(dāng)異常拋出時(shí),異常處理機(jī)制負(fù)責(zé)搜尋參數(shù)與異常類(lèi)型相匹配的第一個(gè)處理程序,然后進(jìn)入catch語(yǔ)句中執(zhí)行,此時(shí)認(rèn)為異常得到了處理。如果程序塊里面的內(nèi)容很多,前面的代碼拋出了異常,則后面的正常程序?qū)⒉粫?huì)執(zhí)行,系統(tǒng)直接catch捕獲異常并且處理
catch語(yǔ)句可以有多個(gè),用來(lái)匹配多個(gè)異常,捕獲異常的順序與catch語(yǔ)句的順序有關(guān),當(dāng)捕獲到對(duì)應(yīng)的異常對(duì)象時(shí),剩下的catch語(yǔ)句不再進(jìn)行匹配,因此在安排catch語(yǔ)句的順序時(shí),首先應(yīng)該捕獲最特殊的異常,然后一般化。catch的類(lèi)型是Java語(yǔ)言定義的或者程序員自己定義的,表示拋出異常的類(lèi)型。異常的變量名表示拋出異常的對(duì)象的引用,如果catch捕獲并匹配了該異常,那么就可以直接用這個(gè)異常變量名來(lái)指向所匹配的異常,并且在catch語(yǔ)句中直接引用。部分系統(tǒng)生成的異常在Java運(yùn)行時(shí)自動(dòng)拋出,也可通過(guò)throws關(guān)鍵字聲明該方法要拋出的異常,然后在方法內(nèi)拋出異常對(duì)象。
final語(yǔ)句為異常提供一個(gè)統(tǒng)一的出口,一般情況下程序始終都要執(zhí)行final語(yǔ)句,final在程序中可選。final一般是用來(lái)關(guān)閉已打開(kāi)的文件和釋放其他系統(tǒng)資源。try-catch-final可以嵌套。
有4種特殊情況,finally塊不會(huì)被執(zhí)行:
- finally語(yǔ)句塊中發(fā)生了異常
- 前面的代碼中執(zhí)行了System.exit()退出程序
- 程序中所在的線程死亡
- 關(guān)閉CPU
(3)舉例
- 例1:捕獲異常
程序輸出結(jié)果為:
java.lang.ArrayIndexOutOfBoundsException: 0 finally block輸出信息表明程序中捕獲到了一個(gè)ArrayIndexOutOfBoundsException類(lèi)的運(yùn)行時(shí)的異常,是由于main的參數(shù)args[]字符串?dāng)?shù)組沒(méi)有接收到任何輸入造成的。
右擊程序包,選中Run As->Run Configurations,打開(kāi)Run Configurations界面,在Arguments一欄填充數(shù)據(jù)“2”,再次運(yùn)行,運(yùn)行結(jié)果為:
a=5 finally block重新輸入?yún)?shù)“0”,再次以運(yùn)行此程序,程序輸出結(jié)果為:拋出ArithmeticException異常,ArrayIndexOutOfBoundsException異常并沒(méi)有被捕獲。
finally block Exception in thread "main" java.lang.ArithmeticException: / by zeroat com.chapter6.Example6_1.main(Example6_1.java:20)可以將程序改為:
public static void main(String[] args) {try {int i =Integer.parseInt(args[0]);int a = 10/i;System.out.println("a="+a);}catch (ArrayIndexOutOfBoundsException e){System.out.println(e);}catch (ArithmeticException e){System.out.println(e);}finally {System.out.println("finally block");}}運(yùn)行結(jié)果為:拋出ArithmeticException
java.lang.ArithmeticException: / by zero finally block- 例2:匹配多個(gè)異常的catch子句
考慮到該程序運(yùn)行時(shí)可能產(chǎn)生的異常有:當(dāng)沒(méi)有任何輸入時(shí),會(huì)捕獲到ArrayIndexOutOfBoundsException 異常;當(dāng)輸入值為0時(shí),會(huì)捕獲到ArithmeticException 異常,當(dāng)輸入格式不是整數(shù)時(shí),會(huì)捕獲NumberFormatException異常。
通常,為捕獲到所有可能出現(xiàn)的異常,可以在處理異常的末尾,加上Exception 類(lèi),這樣即可以使所有異常都被捕捉到,也可以防止想捕獲具體異常時(shí)被它提前捕獲。
- 例3:多重捕獲
運(yùn)行程序,輸出結(jié)果為:可以看出finally子句總能被執(zhí)行。
有輸入數(shù)字串或輸入格式不正確 finally block(4)關(guān)于return和finally的關(guān)系
- 例1:try中有return
輸出結(jié)果為:
one finally block two finally block從程序運(yùn)行結(jié)果可以看出,無(wú)論在什么位置添加return,finally子句都會(huì)被執(zhí)行。
- 例2:catch和try中都有return
輸出結(jié)果為:
catch語(yǔ)句模塊 finally語(yǔ)句模塊 1當(dāng)try中拋出異常且catch中有return語(yǔ)句,finally中沒(méi)有return語(yǔ)句,java先執(zhí)行catch中非return語(yǔ)句,再執(zhí)行finally語(yǔ)句,最后執(zhí)行return語(yǔ)句。若try中沒(méi)有拋出異常,則程序不會(huì)執(zhí)行catch體里面的語(yǔ)句,java先執(zhí)行try中非return語(yǔ)句,再執(zhí)行finally語(yǔ)句,最后再執(zhí)行try中的return語(yǔ)句。
- 例3:finally 中有return
輸出結(jié)果為:
catch語(yǔ)句模塊 finally語(yǔ)句模塊 2finally中有return時(shí),會(huì)覆蓋掉try和catch中的return。
- 例4:finally中沒(méi)有return語(yǔ)句,但是改變了返回值
先來(lái)看第一個(gè)例子
public class Example6_7 {public static int set() {int a = 1;try {return a;} catch (Exception e) {System.out.println("catch語(yǔ)句");} finally {a = 200;}return a;}public static void main(String[] args) {System.out.println("a="+set());} }可以先猜猜輸出的結(jié)果是什么,接著來(lái)看第2個(gè)例子:
public class Example6_7 {public int a;public Example6_7 set() {try {this.a=10;} catch (Exception e) {System.out.println("catch語(yǔ)句");} finally {System.out.println("finally語(yǔ)句塊");this.a=200;}return this;}public static void main(String[] args) {Example6_7 t=new Example6_7();t.set();System.out.println(t.a);} }可以看到兩段代碼運(yùn)行后的結(jié)果如下:
a=1 finally語(yǔ)句塊 200如果finally中定義的數(shù)據(jù)是基本數(shù)據(jù)類(lèi)型或文本字符串,則在finally中對(duì)該基本數(shù)據(jù)的改變不起作用,try中的return語(yǔ)句依然會(huì)返回進(jìn)入finally塊中之前保存的值;如果finally中定義的數(shù)據(jù)是是引用類(lèi)型,則finally中的語(yǔ)句會(huì)起作用,try中return語(yǔ)句的值就是在finally中改變后該屬性的值。
(5)使用場(chǎng)景
針對(duì)需要如何處理的異常,采用捕獲的方式去處理異常。
5.Java異常處理過(guò)程——聲明異常throws
(1)定義
如果一個(gè)方法可能會(huì)出現(xiàn)異常,但沒(méi)有能力處理這種異常,可以在方法聲明處用throws子句來(lái)聲明拋出異常。用它修飾的方法向調(diào)用者表明該方法可能會(huì)拋出異常(可以是一種類(lèi)型,也可以是多種類(lèi)型,用逗號(hào)隔開(kāi))(位置: 寫(xiě)在方法名 或方法名列表之后 ,在方法體之前。)
(2)結(jié)構(gòu)語(yǔ)法
static void pop() throws Exception1,Exception2,Exception3{//方法體}(3)throws與throw的區(qū)別
- throw 在方法體內(nèi)使用,throws 函數(shù)名后或者參數(shù)列表后方法體前
- 意義 : throw 強(qiáng)調(diào)動(dòng)作,而throws 表示一種傾向、可能但不一定實(shí)際發(fā)生
- throws 后面跟的是異常類(lèi),可以一個(gè),可以多個(gè),多個(gè)用逗號(hào)隔開(kāi)。throw 后跟的是異常對(duì)象。
(4)舉例
public class Example6_3 { //定義方法并拋出NegativeArraySizeException異常static void pop() throws NegativeArraySizeException{int[] arr = new int[-5];}public static void main(String[] args){try {//處理異常信息pop();//調(diào)用pop方法}catch (NegativeArraySizeException e){System.out.println("pop()方法拋出的異常");//輸出異常消息}} }使用throws關(guān)鍵字將異常拋給調(diào)用者后,如果調(diào)用者不想處理該異常,可以繼續(xù)向上拋出,但最終要有能夠處理該異常的調(diào)用者。pop方法中沒(méi)有處理異常NegativeArraySizeException,而是main函數(shù)來(lái)處理。
(5)使用場(chǎng)景
- 非檢查異常(運(yùn)行時(shí)異常)可以不使用throws關(guān)鍵字來(lái)聲明要拋出的異常,編譯也可順利通過(guò),但在運(yùn)行時(shí)會(huì)被系統(tǒng)拋出。
- 受檢異常(編譯時(shí)異常),必須使用try-catch/throws處理,否則會(huì)導(dǎo)致編譯錯(cuò)誤。
- 僅當(dāng)拋出了異常,該方法的調(diào)用者才必須處理或重新拋出該異常。當(dāng)方法的調(diào)用者無(wú)力處理該異常時(shí),應(yīng)該繼續(xù)拋出而不是直接調(diào)用方法。
- 調(diào)用方法必須遵循一個(gè)原則:若覆蓋一個(gè)方法,則不能聲明與覆蓋方法不同的異常,聲明的任何異常必須是被覆蓋方法所聲明異常的同類(lèi)或子類(lèi)。如下例子:
6.Java異常處理過(guò)程——拋出異常throw
(1)定義
Java程序的當(dāng)前方法或自身不去處理異常,選擇在方法內(nèi)部使用throw拋出一個(gè)Throwable類(lèi)型的異常。
(2)結(jié)構(gòu)語(yǔ)法
- 關(guān)鍵字是throw,throw語(yǔ)句拋出的是異常類(lèi)對(duì)象,因此需要new關(guān)鍵字創(chuàng)建這一異常實(shí)例,而且只能拋出一個(gè)異常實(shí)例。
- throw在方法體中,程序會(huì)在throw語(yǔ)句后立即終止,它后面的語(yǔ)句執(zhí)行不到,然后在包含它的所有try塊中(可能在上層調(diào)用函數(shù)中)從里到外尋找含有與其匹配的catch子句的try塊。
- new 的異常類(lèi)名稱必須是Throwable或其子類(lèi)
(3)舉例
- 例1
運(yùn)行結(jié)果:
除數(shù)不能為0上面的例子中,b=0,引發(fā)了ArithmeticException異常,因此創(chuàng)建了ArithmeticException對(duì)象,并由throw語(yǔ)句將異常拋給Java運(yùn)行時(shí)系統(tǒng),系統(tǒng)尋找匹配的異常處理器catch并運(yùn)行相應(yīng)的異常處理代碼,打印輸出”除數(shù)不能為0“。try-catch語(yǔ)句結(jié)束。
實(shí)際上,除數(shù)為0等于ArithmeticException,是RuntimeException的子類(lèi),運(yùn)行時(shí)異常將由系統(tǒng)自動(dòng)拋出,不需要使用throw語(yǔ)句,上面的代碼等價(jià)于如下代碼:
public class Example6_5 {public static void main(String[] args) {int a = 6;int b = 0;try { System.out.println(a / b);}catch (ArithmeticException e){System.out.println("除數(shù)不能為0");}} }- 例2:
程序運(yùn)行的結(jié)果為:
除數(shù)不能為0 false可以看到finally語(yǔ)句塊中的return會(huì)覆蓋掉catch里面的throw拋出的異常
- 例3:
可以猜測(cè)一下程序的運(yùn)行結(jié)果:
除數(shù)不能為0 捕獲可以看到同樣finally里面的throw會(huì)覆蓋catch里面的return
(4)使用場(chǎng)景
- 針對(duì)不知道如何處理的異常,采用拋出的方式去處理。
- throw可拋出系統(tǒng)自定義異常,通常情況下,是用來(lái)拋出用戶自定義的異常。
- throw后面不能跟其它代碼塊,否則編譯不能通過(guò),但是可以在finally語(yǔ)句塊中有return語(yǔ)句,finally語(yǔ)句可以讓throw和return共存
四、自定義異常
1.定義
繼承Throwable或者他的子類(lèi)Exception的用戶自己定義的異常類(lèi)。前面的內(nèi)容提到的都是系統(tǒng)有的異常類(lèi)。
2.在程序中使用自定義異常的步驟
- 創(chuàng)建自定義異常類(lèi)
- 在方法中通過(guò)throw拋出異常對(duì)象
- 如果在當(dāng)前方法中對(duì)拋出的異常對(duì)象作處理,可以使用try-catch語(yǔ)句塊捕獲拋出異常對(duì)象并且處理,否則要在方法的聲明處通過(guò)throws關(guān)鍵字指明要拋出給方法調(diào)用者的異常。
- 在出現(xiàn)異常方法的調(diào)用者中捕獲并處理異常
3.結(jié)構(gòu)語(yǔ)法
class UserException extends Exception {UserException(){super();...//其他語(yǔ)句} }throw關(guān)鍵字通常用在方法體中,并且拋出一個(gè)異常對(duì)象
4.舉例
- 例1
輸出結(jié)果是:
除數(shù)不能為0- 例2
創(chuàng)建自定義異常類(lèi)AgeException,繼承自類(lèi)Exception。使用Throw關(guān)鍵字拋出異常對(duì)象。
input方法用于接收從鍵盤(pán)輸入的姓名和年齡,如果輸入為負(fù)數(shù),則會(huì)拋出AgeException異常并積極捕獲處理,如果輸入正確,則會(huì)將姓名和年齡輸出同時(shí)結(jié)束整個(gè)程序。
輸出結(jié)果是:
請(qǐng)輸入姓名: jack 請(qǐng)輸入年齡: -20 年齡不能為負(fù)數(shù)請(qǐng)重新輸入: -34 年齡不能為負(fù)數(shù)請(qǐng)重新輸入: -5 年齡不能為負(fù)數(shù)請(qǐng)重新輸入: 11 姓名jack 年齡11例3:
public class InterfaceException extends RuntimeException {private Integer code;private String msg;public InterfaceException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}public Integer getCode() {return this.code;}public String getMsg() {return this.msg;}public void setCode(final Integer code) {this.code = code;}public void setMsg(final String msg) {this.msg = msg;}} @PostMapping(value = "/addSeniorMembers")public Result addSeniorMembers(@RequestBody MembersList membersList) {if (ObjectUtil.isNotEmpty(membersList)){return flowRecordService.save(membersList);}else {throw new InterfaceException(1001,"參數(shù)錯(cuò)誤");}}注意:異常在方法內(nèi)throw拋出后,需要在method上通過(guò)throws拋出
5.系統(tǒng)定義的異常與用戶定義的異常區(qū)別
系統(tǒng)定義的異常是特定情況出現(xiàn)的問(wèn)題,而此時(shí)用來(lái)對(duì)可能遇到的問(wèn)題進(jìn)行處理。用戶定義的異常是自己覺(jué)得可能會(huì)出現(xiàn)問(wèn)題時(shí),需要處理的。這樣避免程序中斷或是出現(xiàn)未知錯(cuò)誤。
系統(tǒng)異常有兩種一種是運(yùn)行時(shí)異常,一種是普通異常,普通異常要求用戶捕獲或者拋出的,不捕獲或者拋出就會(huì)編譯不通過(guò)。運(yùn)行時(shí)異常編譯可以通過(guò),但是運(yùn)行時(shí)才顯露出來(lái)。
五、Try-With-Resources
-
Java庫(kù)中有很多資源需要手動(dòng)關(guān)閉,例如打開(kāi)的文件、連接的數(shù)據(jù)庫(kù)等。在java7之前都是try-finally的方式關(guān)閉資源,try后面總是跟著一個(gè)“{”。
-
舉個(gè)例子:try-finally方式關(guān)閉資源
從上例可以看出,這種實(shí)現(xiàn)非常的雜亂冗長(zhǎng)。
Java7之后,推出了Try-With-Resources聲明代替之前的方式,try后跟括號(hào)"(",括號(hào)內(nèi)的部分稱為資源規(guī)范頭。**資源規(guī)范頭中可以包含多個(gè)定義,通過(guò)分號(hào)進(jìn)行分隔。**規(guī)范頭中定義的對(duì)象必須實(shí)現(xiàn)java.lang.AntoCloseable接口,這個(gè)接口中有一個(gè)close()方法,因此無(wú)論是否正常退出try語(yǔ)句塊,這些對(duì)象都會(huì)在try語(yǔ)句塊運(yùn)行結(jié)束之后調(diào)用close方法,從而替代以前的在finally中關(guān)閉資源的功能,且不需要冗長(zhǎng)的代碼,另外,Try-With-Resources中的try語(yǔ)句可以不包含catch或者finally語(yǔ)句塊而獨(dú)立存在。
public class Example6_9 {public static void main(String[] args) {copy("E:/MyFirst.java","F:/First.Java");//復(fù)制文件}private static void copy(String src, String des) {try (InputStream in = new FileInputStream(src);OutputStream out = new FileOutputStream(des)) {byte[] buff = new byte[1024];//創(chuàng)建一個(gè)長(zhǎng)度為1024字節(jié)的字節(jié)數(shù)組int n;//從輸入流一次最多流入buff.length個(gè)字節(jié)的數(shù)據(jù)到buff中,直到文件末尾結(jié)束while ((n=in.read(buff))>=0){//將數(shù)組buff中的數(shù)據(jù)從0位置開(kāi)始,長(zhǎng)度為n的字節(jié)輸出到輸出流中out.write(buff,0,n);}}catch (IOException e){e.printStackTrace();}} }六、異常的使用原則
Java異常強(qiáng)制用戶去考慮程序的健壯性和安全性,異常處理不用來(lái)控制程序的正常流程,其主要作用是捕獲程序在運(yùn)行時(shí)發(fā)生的異常并進(jìn)行相應(yīng)的處理。編寫(xiě)代碼處理某個(gè)異常時(shí)可遵循以下的一些原則:
七、三層架構(gòu)異常處理
1、dao層不捕獲異常、不拋出異常:spring框架將底層的數(shù)據(jù)庫(kù)checked異常封裝成unchecked異常了
2、service層捕獲異常,并拋出自定義unchecked異常,拋出的異常定義狀態(tài)碼:checked異常默認(rèn)情況事務(wù)不會(huì)回滾?.? (如果不拋出異常事務(wù)不會(huì)回滾)
3、controller層捕獲unchecked異常, 處理返回結(jié)果.
4、exceptionHandler中統(tǒng)一處理所有沒(méi)有捕獲異常
總結(jié)
以上是生活随笔為你收集整理的Java异常详解及自定义异常的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: AKAI Professional MP
- 下一篇: (转载)来一本奥运版圣经?