項(xiàng)目10 異常處理_第1頁(yè)
項(xiàng)目10 異常處理_第2頁(yè)
項(xiàng)目10 異常處理_第3頁(yè)
項(xiàng)目10 異常處理_第4頁(yè)
項(xiàng)目10 異常處理_第5頁(yè)
已閱讀5頁(yè),還剩26頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

付費(fèi)下載

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

Java程序設(shè)計(jì)專(zhuān)業(yè)核心課程

精品課程1教學(xué)計(jì)劃ORJECT了解Java程序異常類(lèi)繼承。了解Java中的多重捕獲。理解Java語(yǔ)言中的釋放資源。理解Java語(yǔ)言中的自定義異常類(lèi)。1精品課程210.1Java異常Java提供了try(嘗試)、catch(捕捉)、finally(最終)這三個(gè)關(guān)鍵字來(lái)處理異常。在處理各種異常時(shí),需要用到對(duì)應(yīng)的異常類(lèi),指的是由程序拋出的對(duì)象所屬的類(lèi),常見(jiàn)的異常分類(lèi)如下:(1)空指針異常(java.lang.NullPointerException)。發(fā)生此異常情況一般是字符串變量未初始化、數(shù)組未初始化、類(lèi)對(duì)象未初始化,還有一種情況是當(dāng)對(duì)象為空時(shí)并沒(méi)有判斷其是否為空值。為了避免這種情況,除了檢查變量、數(shù)組、對(duì)象等是否初始化之外,如有必要?jiǎng)t要加上判斷是否為null的if語(yǔ)句。(2)指定的類(lèi)不存在(java.lang.ClassNotFoundException)。出現(xiàn)這個(gè)錯(cuò)誤的原因之一是缺包,這時(shí)只要下載并導(dǎo)入相應(yīng)的包即可。但當(dāng)已經(jīng)把包導(dǎo)入的,又報(bào)了這種錯(cuò)誤,這就需要人們?cè)诰庉嬈髦羞M(jìn)行調(diào)整設(shè)置了。在使用tomcat時(shí),要先檢查lib中是否導(dǎo)入了jar。3精品課程(3)字符串轉(zhuǎn)換為數(shù)字異常(java.lang.NumberFormatException)。這個(gè)錯(cuò)誤就是字符串中出現(xiàn)非數(shù)字型字符,轉(zhuǎn)換為數(shù)字時(shí)發(fā)生異常。除此之外,如果字符串轉(zhuǎn)換為數(shù)字(比如string轉(zhuǎn)int、string轉(zhuǎn)double)時(shí)超過(guò)了類(lèi)型的范圍,也會(huì)出現(xiàn)這個(gè)錯(cuò)誤。解決該問(wèn)題的方法就是在轉(zhuǎn)換之前先對(duì)字符串進(jìn)行檢查。(4)數(shù)組下標(biāo)越界異常(java.lang.IndexOutOfBoundsException)。數(shù)組下標(biāo)越界異常是指取的數(shù)組元素在數(shù)組中并沒(méi)有定義出來(lái),比如定義了一個(gè)長(zhǎng)度為5的數(shù)組a,當(dāng)你想取a[6]元素時(shí)肯定會(huì)出錯(cuò)。解決這類(lèi)問(wèn)題就是要注意數(shù)組的長(zhǎng)度,有時(shí)為了減少空間浪費(fèi),人們會(huì)使用動(dòng)態(tài)數(shù)組構(gòu)建方法,這時(shí)在對(duì)數(shù)組進(jìn)行操作時(shí)建議先用length獲取其數(shù)組長(zhǎng)度,從而規(guī)避錯(cuò)誤。(5)數(shù)學(xué)運(yùn)算異常(java.lang.ArithmeticException)。除數(shù)為0時(shí)會(huì)報(bào)出該錯(cuò)誤,解決方法是避免除數(shù)為0。可以將這個(gè)錯(cuò)誤解讀為“出現(xiàn)異常的運(yùn)算條件”,除了除數(shù)為0的情況之外,可能還有其他的異常情況,可以根據(jù)具體情況進(jìn)行分析。(6)沒(méi)有訪問(wèn)權(quán)限(java.lang.IllegalAccessException)。屬于權(quán)限問(wèn)題,在程序訪問(wèn)某方法時(shí)注意一下訪問(wèn)權(quán)限即可(public/private),這種錯(cuò)誤在使用package時(shí)容易發(fā)生。(7)方法的參數(shù)錯(cuò)誤(java.lang.IllegalArgumentException)。在調(diào)用帶有參數(shù)的方法時(shí),請(qǐng)注意傳遞的參數(shù)是否正確。(8)數(shù)據(jù)類(lèi)型轉(zhuǎn)換異常(java.lang.ClassCastException)。在進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換時(shí)容易發(fā)生該錯(cuò)誤,在進(jìn)行轉(zhuǎn)換前要先對(duì)類(lèi)型進(jìn)行判別,規(guī)避錯(cuò)誤。(9)文件未找到異常(java.lang.FileNotFoundException)。當(dāng)程序試圖打開(kāi)一個(gè)不存在的文件進(jìn)行讀寫(xiě)操作時(shí)會(huì)報(bào)出該錯(cuò)誤,通常由FileInputStream、FileOutputStream、RandomAccessFile的構(gòu)造器聲明發(fā)出,即使文件存在,但因某些原因無(wú)法訪問(wèn),也會(huì)報(bào)出該錯(cuò)誤。(10)數(shù)組存儲(chǔ)異常(java.lang.ArrayStoreException)。假如在int型數(shù)組中存入string類(lèi)型的變量,就會(huì)報(bào)錯(cuò),解決方案是在存入對(duì)象時(shí)查明類(lèi)型,或者在存入前先進(jìn)行類(lèi)型轉(zhuǎn)換。(11)方法不存在異常(java.lang.NoSuchMethodException)。程序所要調(diào)用的方法不存在就會(huì)出現(xiàn)此異常,解決方法是不調(diào)用或者構(gòu)造其方法。(12)文件已結(jié)束異常(java.lang.EOFException)。程序輸入過(guò)程中遇到文件或流的結(jié)尾會(huì)引發(fā)該異常,此異常用于檢查是否達(dá)到文件或流結(jié)尾。(13)實(shí)例化異常(java.lang.InstantiationException)。類(lèi)創(chuàng)建新對(duì)象時(shí)無(wú)法通過(guò)構(gòu)造器進(jìn)行實(shí)例化引發(fā)的異常,解決方案是構(gòu)造方法。(14)被中止異常(java.lang.InterruptedException)。通過(guò)其他線程的Thread的interrupt方法中止另一個(gè)線程時(shí)報(bào)出的錯(cuò)誤,解決方法如下:①不做處理,直接拋出。②捕獲異常,再次調(diào)用interrupt方法,將中斷狀態(tài)重新設(shè)置為true。4精品課程5精品課程(15)不支持克隆異常(java.lang.CloneNotSupportedException)。如果沒(méi)有實(shí)現(xiàn)Cloneable接口便調(diào)用了clone方法,且報(bào)出該錯(cuò)誤。若類(lèi)不支持Cloneable接口,調(diào)用時(shí)也會(huì)出現(xiàn)該錯(cuò)誤。解決方法是實(shí)現(xiàn)Cloneable接口。(16)輸入輸出異常(IOException)。該異常為Exception的一個(gè)分支,通常發(fā)生在文件的數(shù)據(jù)讀寫(xiě)上。(17)錯(cuò)誤(java.lang.Error)。所有錯(cuò)誤的基類(lèi),用于標(biāo)識(shí)嚴(yán)重的程序運(yùn)行問(wèn)題。通常是訪問(wèn)外部資源時(shí)出現(xiàn)一系列問(wèn)題,解決方案也需要圍繞訪問(wèn)外部資源這一重點(diǎn)展開(kāi)。10.1.1?Java異常處理機(jī)制【例10.1】為了學(xué)習(xí)Java異常處理機(jī)制,首先了解下面的程序。//HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){inta=0;System.out.println(5/a);}}這個(gè)程序沒(méi)有編譯錯(cuò)誤,但會(huì)發(fā)生如下的運(yùn)行時(shí)錯(cuò)誤。Exceptioninthread"main"java.lang.ArithmeticException:/byzeroatcom.a51work6.HelloWorld.main(HelloWorld.java:9)在數(shù)學(xué)上除數(shù)不能為0,所以程序運(yùn)行時(shí)表達(dá)式(5/a)會(huì)拋出ArithmeticException異常,ArithmeticException是數(shù)學(xué)計(jì)算異常,凡是發(fā)生數(shù)學(xué)計(jì)算錯(cuò)誤都會(huì)拋出該異常。程序運(yùn)行過(guò)程中難免會(huì)發(fā)生異常,發(fā)生異常并不可怕,程序員應(yīng)該考慮到有可能發(fā)生哪些異常,編程時(shí)應(yīng)該捕獲并進(jìn)行處理,不能讓程序發(fā)生終止,這就是健壯的程序。6精品課程10.1.2?異常類(lèi)繼承層次異常封裝成為類(lèi)Exception,此外,還有Throwable和Error類(lèi)。異常類(lèi)繼承層次如圖10-1所示。圖10-1Java異常類(lèi)繼承層次10.1.3?Throwable類(lèi)所有的異常類(lèi)都直接或間接地繼承于java.lang.Throwable類(lèi),在Throwable類(lèi)中有以下幾個(gè)非常重要的方法。(1)StringgetMessage():獲得發(fā)生異常的詳細(xì)消息。(2)voidprintStackTrace():打印異常堆棧跟蹤信息。(3)StringtoString():獲得異常對(duì)象的描述?!纠?0.2】接下來(lái)介紹Throwable類(lèi)的使用,將例10.1中的代碼修改成如下代碼。//HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){inta=0;intresult=divide(5,a);System.out.printf("divide(%d,%d)=%d",5,a,result);}publicstaticintdivide(intnumber,intdivisor){try{returnnumber/divisor;}catch(Throwablethrowable){①System.out.println("getMessage():"+throwable.getMessage());②System.out.println("toString():"+throwable.toString());③System.out.println("printStackTrace()輸出信息如下:");throwable.printStackTrace();④}7精品課程return0;}}其運(yùn)行結(jié)果如下。getMessage():/byzerotoString():java.lang.ArithmeticException:/byzeroprintStackTrace()輸出信息如下:java.lang.ArithmeticException:/byzeroatcom.a51work6.HelloWorld.divide(HelloWorld.java:17)atcom.a51work6.HelloWorld.main(HelloWorld.java:10)divide(5,0)=0將可以發(fā)生異常的語(yǔ)句System.out.println(5/a)放到try-catch代碼塊中,稱(chēng)為捕獲異常,有關(guān)捕獲異常的相關(guān)知識(shí)將會(huì)在下一節(jié)中詳細(xì)介紹。在catch中有一個(gè)Throwable對(duì)象throwable(代碼第①行),它是系統(tǒng)在程序發(fā)生異常時(shí)創(chuàng)建的,通過(guò)throwable對(duì)象可以調(diào)用Throwable中定義的方法。代碼第②行是調(diào)用getMessage()方法來(lái)獲得異常消息,輸出結(jié)果是/byzero。代碼第③行是調(diào)用toString()方法來(lái)獲得異常對(duì)象的描述,輸出結(jié)果是java.lang.ArithmeticException:/byzero。代碼第④行是調(diào)用printStackTrace()方法打印異常堆棧跟蹤信息。8精品課程堆棧跟蹤信息從下往上是方法調(diào)用的順序。首先JVM調(diào)用的是com.a51work6.HelloWorld類(lèi)的main方法,接著在HelloWorld.java源代碼第10行調(diào)用com.a51work6.HelloWorld類(lèi)的divide方法,在HelloWorld.java源代碼第17行發(fā)生了異常,最后輸出的是異常信息。10.1.3?Error和ExceptionThrowable有兩個(gè)直接子類(lèi):Error和Exception。1.ErrorError是程序無(wú)法修復(fù)的嚴(yán)重錯(cuò)誤,程序員也根本無(wú)能為力,只能讓程序終止。例如,JVM內(nèi)部錯(cuò)誤、內(nèi)存溢出和資源耗盡等都屬于Error。2.ExceptionException是程序可以修復(fù)的異常,它是程序員所能掌控的。例如,除零異常、空指針訪問(wèn)、網(wǎng)絡(luò)連接中斷和讀取不存在的文件等。本章所討論的異常處理就是對(duì)Exception及其子類(lèi)的異常進(jìn)行處理。10.1.4?受檢查異常和運(yùn)行時(shí)異常Exception類(lèi)可以分為受檢查異常和運(yùn)行時(shí)異常。1.受檢查異常受檢查異常是除RuntimeException以外的異常類(lèi),它們的共同特點(diǎn)是編譯器會(huì)檢查這類(lèi)異常是否進(jìn)行了處理,即要么捕獲(try-catch語(yǔ)句),要么不拋出(通過(guò)在方法后聲明throws),否則會(huì)發(fā)生編譯錯(cuò)誤。受檢查異常種類(lèi)很多,如前文中介紹的日期解析異常ParseException就屬于受檢查異常。2.運(yùn)行時(shí)異常運(yùn)行時(shí)異常是繼承RuntimeException類(lèi)的直接或間接子類(lèi),往往是由程序員所犯錯(cuò)誤而導(dǎo)致的,健壯的程序不應(yīng)該發(fā)生運(yùn)行時(shí)異常。運(yùn)行時(shí)異常的共同特點(diǎn)是編譯器不檢查其是否進(jìn)行了處理,也就是對(duì)于這類(lèi)異常不捕獲也不拋出,程序也可以編譯通過(guò)。由于沒(méi)有進(jìn)行異常處理,一旦運(yùn)行時(shí)異常發(fā)生就會(huì)導(dǎo)致程序的終止,這是用戶(hù)不希望看到的。例如,例10.1中的ArithmeticException異常就屬于RuntimeException異常,可以不用加try_x0002_catch語(yǔ)句捕獲異常。9精品課程10精品課程【例10.3】對(duì)于運(yùn)行時(shí)異常通常不采用拋出或捕獲處理方式,而是應(yīng)該提前預(yù)判,防止這種異常發(fā)生,做到未雨綢繆。例10.1中,在進(jìn)行除法運(yùn)算之前應(yīng)該判斷除數(shù)是非0的,修改為如下代碼。//HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){inta=0;intresult=divide(5,a);System.out.printf("divide(%d,%d)=%d",5,a,result);}publicstaticintdivide(intnumber,intdivisor){//判斷除數(shù)divisor非零,防止運(yùn)行時(shí)異常if(divisor!=0){returnnumber/divisor;}return0;}}11精品課程從代碼可見(jiàn),提前預(yù)判處理要比通過(guò)try-catch捕獲異常要友好得多。除了如圖10-1所示的異常,還有很多異常,隨著學(xué)習(xí)的深入本書(shū)還會(huì)介紹一些常用的異常,其他異常讀者可以自己查詢(xún)API文檔學(xué)習(xí)。10.2捕獲異常在現(xiàn)實(shí)生活中大家是如何對(duì)待領(lǐng)導(dǎo)交待的任務(wù)呢?通常分為兩種情況:自己有能力解決的自己處理;自己沒(méi)有能力解決的反饋給領(lǐng)導(dǎo)。實(shí)際上對(duì)待受檢查異常也是如此。使用當(dāng)前方法可以解決,則捕獲異常進(jìn)行處理;如無(wú)法解決,則拋給上層調(diào)用方法處理。如果上層調(diào)用方法還無(wú)法解決,則繼續(xù)拋給其上一層調(diào)用方法,異常就是這樣向上傳遞,直到有方法對(duì)其進(jìn)行處理,如果所有的方法都不能處理該異常,那么JVM會(huì)終止程序的運(yùn)行。10.2.1?try-catch語(yǔ)句捕獲異常是通過(guò)try-catch語(yǔ)句實(shí)現(xiàn)的,最基本的try-catch語(yǔ)句語(yǔ)法格式如下:try{//可能會(huì)發(fā)生異常的語(yǔ)句}catch(Throwablee){//處理異常e}1.try代碼塊try代碼塊中應(yīng)該包含執(zhí)行過(guò)程中可能會(huì)發(fā)生異常的語(yǔ)句。一條語(yǔ)句是否有可能發(fā)生異常,這要看語(yǔ)句中調(diào)用的方法。例如,日期格式化類(lèi)DateFormat的日期解析方法parse(),該方法的完整定義如下:publicDateparse(Stringsource)throwsParseException方法后面的throwsParseException說(shuō)明,當(dāng)調(diào)用parse()方法時(shí)有可能產(chǎn)生ParseException異常。2.catch代碼塊每個(gè)try代碼塊可以有一個(gè)或多個(gè)catch代碼塊,用于處理try代碼塊中可能發(fā)生的多種異常。catch(Throwablee)語(yǔ)句中的e是捕獲異常對(duì)象,e必須是Throwable的子類(lèi),異常對(duì)象e的作用域在該catch代碼塊中?!纠?0.4】try-catch示例。代碼如下://HelloWorld.java文件packagecom.a51work6;importjava.text.DateFormat;importjava.text.ParseException;importjava.text.SimpleDateFormat;importjava.util.Date;publicclassHelloWorld{publicstaticvoidmain(String[]args){Datedate=readDate();System.out.println("日期="+date);}//解析日期publicstaticDatereadDate(){①try{Stringstr="2018-8-18"//"201A-18-18"DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");12精品課程命令說(shuō)明快捷鍵重命名重命名所選擇的

Java

元素Alt+Shift+R移動(dòng)移動(dòng)所選擇的

Java

元素Alt+Shift+V抽取方法創(chuàng)建一個(gè)包含當(dāng)前所選語(yǔ)句或表達(dá)式的新方法,并相關(guān)的引用Alt+Shift+M抽取局部變量創(chuàng)建為當(dāng)前所選表達(dá)式指定的新變量,并將選擇替換為對(duì)新變量的引用Alt+Shift+L命令說(shuō)明快捷鍵重命名重命名所選擇的

Java

元素Alt+Shift+R移動(dòng)移動(dòng)所選擇的

Java

元素Alt+Shift+V抽取方法創(chuàng)建一個(gè)包含當(dāng)前所選語(yǔ)句或表達(dá)式的新方法,并相關(guān)的引用Alt+Shift+M抽取局部變量創(chuàng)建為當(dāng)前所選表達(dá)式指定的新變量,并將選擇替換為對(duì)新變量的引用Alt+Shift+L命令說(shuō)明快捷鍵重命名重命名所選擇的

Java

元素Alt+Shift+R移動(dòng)移動(dòng)所選擇的

Java

元素Alt+Shift+V抽取方法創(chuàng)建一個(gè)包含當(dāng)前所選語(yǔ)句或表達(dá)式的新方法,并相關(guān)的引用Alt+Shift+M抽取局部變量創(chuàng)建為當(dāng)前所選表達(dá)式指定的新變量,并將選擇替換為對(duì)新變量的引用Alt+Shift+L命令說(shuō)明快捷鍵重命名重命名所選擇的

Java

元素Alt+Shift+R移動(dòng)移動(dòng)所選擇的

Java

元素Alt+Shift+V抽取方法創(chuàng)建一個(gè)包含當(dāng)前所選語(yǔ)句或表達(dá)式的新方法,并相關(guān)的引用Alt+Shift+M抽取局部變量創(chuàng)建為當(dāng)前所選表達(dá)式指定的新變量,并將選擇替換為對(duì)新變量的引用Alt+Shift+L//從字符串中解析日期Datedate=df.parse(str);②returndate;}catch(ParseExceptione){③System.out.println("處理ParseException…");e.printStackTrace();④}returnnull;}}上述代碼第①行中定義了一個(gè)靜態(tài)方法用來(lái)將字符串解析成日期,但并非所有的字符串都是有效的日期字符串,因此調(diào)用代碼第②行的解析方法parse()有可能發(fā)生ParseException異常,ParseException是受檢查異常,在本例中使用try-catch捕獲。代碼第③行的e就是ParseException對(duì)象。代碼第④行的e.printStackTrace()是打印異常堆棧跟蹤信息,本例中的"2018-8-18"字符串是有個(gè)有效的日期字符串,因此不會(huì)發(fā)生異常。如果將字符串改為無(wú)效的日期字符串,如"201A-18-18",則會(huì)打印信息。10.2.2?處理ParseException異常代碼如下:java.text.ParseException:Unparseabledate:"201A-18-18"日期=nullatjava.text.DateFormat.parse(UnknownSource)atcom.a51work6.HelloWorld.readDate(HelloWorld.java:24)atcom.a51work6.HelloWorld.main(HelloWorld.java:13)14精品課程在捕獲到異常之后,通過(guò)e.printStackTrace()語(yǔ)句打印異常堆棧跟蹤信息,往往只是用于調(diào)試,給程序員提示信息。堆棧跟蹤信息對(duì)用戶(hù)其實(shí)是沒(méi)有意義的。例10.4中如果出現(xiàn)異常很有可能是用戶(hù)輸入的日期無(wú)效,捕獲到異常之后給用戶(hù)彈出一個(gè)對(duì)話框,提示用戶(hù)輸入日期無(wú)效,請(qǐng)用戶(hù)重新輸入,用戶(hù)重新輸入后再重新調(diào)用上述方法,這才是捕獲異常之后的正確處理方案。10.2.3?多個(gè)catch代碼塊如果try代碼塊中有很多語(yǔ)句會(huì)發(fā)生異常,而且發(fā)生的異常種類(lèi)又很多,那么可以在try后面跟有多個(gè)catch代碼塊,其語(yǔ)法格式如下:try{//可能會(huì)發(fā)生異常的語(yǔ)句}catch(Throwablee){//處理異常e}catch(Throwablee){//處理異常e}catch(Throwablee){//處理異常e}在有多個(gè)catch代碼的情況下,只要一個(gè)catch代碼塊捕獲到一個(gè)異常,其他的catch代碼塊就不再進(jìn)行匹配?!纠?0.5】多個(gè)catch代碼塊示例。代碼如下://HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){Datedate=readDate();System.out.println("讀取的日期="+date);}publicstaticDatereadDate(){FileInputStreamreadfile=null;InputStreamReaderir=null;BufferedReaderin=null;try{readfile=newFileInputStream("readme.txt");①ir=newInputStreamReader(readfile);in=newBufferedReader(ir);//讀取文件中的一行數(shù)據(jù)Stringstr=in.readLine();②if(str==null){returnnull;}DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=df.parse(str);③returndate;}catch(FileNotFoundExceptione){④System.out.println("處理FileNotFoundException...");e.printStackTrace();}catch(IOExceptione){⑤System.out.println("處理IOException...");e.printStackTrace();}catch(ParseExceptione){⑥System.out.println("處理ParseException...");e.printStackTrace();}returnnull;}}上述代碼通過(guò)JavaI/O流技術(shù)從文件readme.txt中讀取字符串,然后解析成為日期。由于JavaI/O技術(shù)還沒(méi)有介紹,讀者先不要關(guān)注I/O技術(shù)的細(xì)節(jié),只考慮調(diào)用這種方法會(huì)發(fā)生異常即可。在try代碼塊中第①行代碼調(diào)用FileInputStream構(gòu)造方法會(huì)發(fā)生FileNotFoundException異常。第②行代碼調(diào)用BufferedReader輸入流的readLine()方法會(huì)發(fā)生IOException異常。從圖10-1中可知,F(xiàn)ileNotFoundException異常是IOException異常的子類(lèi),應(yīng)該先捕獲FileNotFoundException,見(jiàn)代碼第④行,后捕獲IOException,見(jiàn)代碼第⑤行。如果將FileNotFoundException和IOException捕獲順序交換,代碼如下:try{//可能會(huì)發(fā)生異常的語(yǔ)句}catch(IOExceptione){//IOException異常處理}catch(FileNotFoundExceptione){//FileNotFoundException異常處理}那么永遠(yuǎn)不會(huì)進(jìn)入第二個(gè)catch代碼塊,即FileNotFoundException異常處理永遠(yuǎn)不會(huì)被執(zhí)行。由于上述代碼第⑥行ParseException異常與IOException和FileNotFoundException異常沒(méi)有父子關(guān)系,捕獲ParseException異常的位置可以隨意放置。10.2.4?try-catch語(yǔ)句嵌套【例10.6】Java提供的try-catch語(yǔ)句可以任意嵌套。示例代碼如下://HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){Datedate=readDate();System.out.println("讀取的日期="+date);}publicstaticDatereadDate(){FileInputStreamreadfile=null;InputStreamReaderir=null;BufferedReaderin=null;try{readfile=newFileInputStream("readme.txt");ir=newInputStreamReader(readfile);in=newBufferedReader(ir);try{①Stringstr=in.readLine();②if(str==null){returnnull;}DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=df.parse(str);③returndate;}catch(ParseExceptione){System.out.println("處理ParseException...");e.printStackTrace();}④}catch(FileNotFoundExceptione){⑤System.out.println("處理FileNotFoundException...");e.printStackTrace();}catch(IOExceptione){⑥System.out.println("處理IOException...");e.printStackTrace();}returnnull;}}上述代碼第①~第④行是捕獲ParseException異常的try-catch語(yǔ)句,這個(gè)try-catch語(yǔ)句就是嵌套在捕獲IOException和FileNotFoundException異常的try-catch語(yǔ)句中。程序執(zhí)行時(shí),內(nèi)層如果發(fā)生異常,首先由內(nèi)層catch進(jìn)行捕獲,如果捕獲不到,則由外層catch捕獲。例如,代碼第②行的readLine()方法可能發(fā)生IOException異常,該異常無(wú)法被內(nèi)層catch捕獲,最后被代碼第⑥行的外層catch捕獲。10.2.5?多重捕獲多個(gè)catch代碼塊客觀上提高了程序的健壯性,但是程序代碼量也大大增加了。有些異常雖然種類(lèi)不同,但捕獲之后的處理是相同的。示例代碼如下:try{//可能會(huì)發(fā)生異常的語(yǔ)句}catch(FileNotFoundExceptione){//調(diào)用方法methodA處理}catch(IOExceptione){//調(diào)用方法methodA處理}catch(ParseExceptione){//調(diào)用方法methodA處理}雖然是三個(gè)不同類(lèi)型的異常,但要求捕獲之后的處理都是調(diào)用methodA方法,是否可以把這些異常合并處理,Java7推出了多重捕獲(multi-catch)技術(shù),可以幫助解決此類(lèi)問(wèn)題。上述代碼可以修改如下:try{//可能會(huì)發(fā)生異常的語(yǔ)句}catch(IOException|ParseExceptione){//調(diào)用方法methodA處理}在catch中,多重捕獲異常用“|”運(yùn)算符連接起來(lái)。10.3釋放資源有時(shí)在try-catch語(yǔ)句中會(huì)占用一些非Java資源,如打開(kāi)文件、網(wǎng)絡(luò)連接、打開(kāi)數(shù)據(jù)庫(kù)連接和使用數(shù)據(jù)結(jié)果集等,這些資源并非Java資源,不能通過(guò)JVM的垃圾收集器回收,需要程序員釋放。為了確保這些資源能夠被釋放,可以使用finally代碼塊或Java7之后提供的自動(dòng)資源管理(AutomaticResourceManagement)技術(shù)。10.3.1?finally代碼塊try-catch語(yǔ)句后面還可以跟一個(gè)finally代碼塊,即try-catch-finally語(yǔ)句語(yǔ)法格式如下:try{//可能會(huì)生成異常語(yǔ)句}catch(Throwablee1){//處理異常e1}catch(Throwablee2){//處理異常e1}catch(ThrowableeN){//處理異常eN}finally{//釋放資源}無(wú)論try正常結(jié)束,還是catch異常結(jié)束,都會(huì)執(zhí)行finally代碼塊,如圖10-2所示。

圖10-2finally代碼塊流程【例10.6】finally代碼塊示例。代碼如下://HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){Datedate=readDate();System.out.println("讀取的日期="+date);}publicstaticDatereadDate(){FileInputStreamreadfile=null;InputStreamReaderir=null;BufferedReaderin=null;try{readfile=newFileInputStream("readme.txt");ir=newInputStreamReader(readfile);in=newBufferedReader(ir);//讀取文件中的一行數(shù)據(jù)Stringstr=in.readLine();if(str==null){returnnull;}DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=df.parse(str);returndate;}catch(FileNotFoundExceptione){System.out.println("處理FileNotFoundException...");e.printStackTrace();}catch(IOExceptione){System.out.println("處理IOException...");e.printStackTrace();}catch(ParseExceptione){System.out.println("處理ParseException...");e.printStackTrace();}finally{①try{if(readfile!=null){readfile.close();②}}catch(IOExceptione){e.printStackTrace();}try{if(ir!=null){ir.close();③}}catch(IOExceptione){e.printStackTrace();}try{if(in!=null){in.close();④}}catch(IOExceptione){e.printStackTrace();}}⑤returnnull;}}上述代碼第①行至第⑤行是finally語(yǔ)句,在這里通過(guò)關(guān)閉流釋放資源,F(xiàn)ileInputStream、InputStreamReader和BufferedReader是三個(gè)輸入流,它們都需要關(guān)閉,見(jiàn)代碼第②行和第④行通過(guò)流的close()關(guān)閉流,但是流的close()方法還有可能發(fā)生IOException異常,所以這里又針對(duì)每一個(gè)close()語(yǔ)句還需要進(jìn)行捕獲處理。需要注意的是,為了使代碼簡(jiǎn)潔,可能有的人會(huì)將finally代碼中的多個(gè)嵌套的try_x0002_catch語(yǔ)句合并,例如,將上述代碼進(jìn)行修改,即將三個(gè)可以發(fā)生異常的close()方法放到一個(gè)try-catch中。讀者可以考慮一下這樣處理是否穩(wěn)妥?每一個(gè)close()方法對(duì)應(yīng)關(guān)閉一個(gè)資源,如果第一個(gè)close()方法關(guān)閉時(shí)發(fā)生了異常,那么后面的兩個(gè)也不會(huì)關(guān)閉,因此以下的程序代碼是有缺陷的。try{...}catch(FileNotFoundExceptione){...}catch(IOExceptione){...}catch(ParseExceptione){...}finally{try{if(readfile!=null){readfile.close();}if(ir!=null){ir.close();}if(in!=null){in.close();}}catch(IOExceptione){e.printStackTrace();}}10.3.2?自動(dòng)資源管理例10.6中使用finally代碼塊釋放資源會(huì)導(dǎo)致程序代碼量大大增加,一個(gè)finally代碼塊往往比正常執(zhí)行的程序還要多。在Java7之后提供自動(dòng)資源管理(AutomaticResourceManagement)技術(shù),可以替代finally代碼塊,優(yōu)化代碼結(jié)構(gòu),提高程序的可讀性。自動(dòng)資源管理是在try語(yǔ)句上的擴(kuò)展,其語(yǔ)法格式如下:try(聲明或初始化資源語(yǔ)句){//可能會(huì)生成異常語(yǔ)句}catch(Throwablee1){//處理異常e1}catch(Throwablee2){//處理異常e2}catch(ThrowableeN){//處理異常eN}在try語(yǔ)句后面添加一對(duì)小括號(hào)“()”,其中是聲明或初始化資源語(yǔ)句,如有多條語(yǔ)句,語(yǔ)句之間用分號(hào)“;”分隔?!纠?0.7】自動(dòng)資源管理示例,代碼如下://HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){Datedate=readDate();System.out.println("讀取的日期="+date);}publicstaticDatereadDate(){//自動(dòng)資源管理try(FileInputStreamreadfile=newFileInputStream("readme.txt");①I(mǎi)nputStreamReaderir=newInputStreamReader(readfile);②BufferedReaderin=newBufferedReader(ir))③{//讀取文件中的一行數(shù)據(jù)Stringstr=in.readLine();if(str==null){returnnull;}DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=df.parse(str);returndate;}catch(FileNotFoundExceptione){System.out.println("處理FileNotFoundException...");e.printStackTrace();}catch(IOExceptione){System.out.println("處理IOException...");e.printStackTrace();}catch(ParseExceptione){System.out.println("處理ParseException...");e.printStackTrace();}returnnull;}}上述代碼第①行至第③行是聲明/初始化三個(gè)輸入流,三條語(yǔ)句放在try語(yǔ)句后面小括號(hào)中,語(yǔ)句之間用分號(hào)“;”分隔,這就是應(yīng)用了自動(dòng)資源管理技術(shù),采用了自動(dòng)資源管理后就不再需要finally代碼塊,即不需要自己close這些資源,釋放過(guò)程交給了JVM。10.3.3?throws與聲明方法拋出異常一個(gè)方法如果能夠處理異常,則需要捕獲并處理。但是如果方法沒(méi)有能力處理該異常,捕獲它也沒(méi)有任何意義,則需要在方法后面聲明拋出該異常,通知上層調(diào)用者該方法有可能發(fā)生異常。在方法后面聲明拋出異常使用throws關(guān)鍵字,這里可以回顧一下成員方法,其語(yǔ)法格式如下:classclassName{[public|protected|private][static][final|abstract][native][synchronized]typemethodName([paramList])[throwsexceptionList]{//方法體}}其中,參數(shù)列表之后的[throwsexceptionList]語(yǔ)句是聲明拋出異常。方法中可能拋出的異常(除了Error和RuntimeException及其子類(lèi)外)都必須通過(guò)throws語(yǔ)句列出,多個(gè)異常之間采用逗號(hào)(,)分隔。需要注意的是,如果聲明拋出的多個(gè)異常類(lèi)之間有父子關(guān)系,可以只聲明拋出父類(lèi)。但如果沒(méi)有父子關(guān)系,最好明確聲明拋出每一個(gè)異常,因?yàn)樯蠈诱{(diào)用者會(huì)根據(jù)這些異常信息進(jìn)行相應(yīng)的處理。假如一個(gè)方法中有可能拋出IOException和ParseException兩個(gè)異常,那么是否可以同時(shí)聲明拋出IOException和ParseException呢?還是只聲明拋出Exception呢?因?yàn)镋xception是IOException和ParseException的父類(lèi),只聲明拋出Exception從語(yǔ)法上是允許的,但是聲明拋出IOException和ParseException更好一些?!纠?0.8】在readDate()方法后聲明拋出異常。示例代碼如下://HelloWorld.java文件packagecom.a51work6;publicclassHelloWorld{publicstaticvoidmain(String[]args){①try{Datedate=readDate();②System.out.println("讀取的日期="+date);}catch(IOExceptione){③System.out.println("處理IOException...");e.printStackTrace();}catch(ParseExceptione){④System.out.println("處理ParseException...");e.printStackTrace();}}publicstaticDatereadDate()throwsIOException,ParseException{⑤//自動(dòng)資源管理FileInputStreamreadfile=newFileInputStream("readme.txt");⑥InputStreamReaderir=newInputStreamReader(readfile);BufferedReaderin=newBufferedReader(ir);//讀取文件中的一行數(shù)據(jù)Stringstr=in.readLine();⑦if(str==null){returnnull;}DateFormatdf=newSimpleDateFormat("yyyy-MM-dd");Datedate=df.parse(str);⑧returndate;}}由于readDate()方法中的代碼第⑥、⑦、⑧行都有可能引發(fā)異常,在readDate()方法內(nèi)又沒(méi)有捕獲處理,所有需要在代碼第⑤行方法后聲明拋出異常,事實(shí)上有三個(gè)異常:FileNotFoundException、IOException和ParseException,由于FileNotFoundException屬于IOException異常,所以只聲明拋出IOException和ParseException即可。一旦在readDate()方法中聲明拋出了異常,那么它的調(diào)用者main()方法也會(huì)面臨同樣的問(wèn)題:要么捕獲異常自己處理,要么將異常拋出給上層調(diào)用者。一旦發(fā)生異常,main()方法也選擇拋出,那么程序運(yùn)行就會(huì)終止。本例中main()方法是捕獲異常進(jìn)行處理,捕獲異常過(guò)程前文已經(jīng)介紹過(guò)了,這里就不再贅述。10.3.4?自定義異常類(lèi)為了提高代碼的可重用性,用戶(hù)可以自行開(kāi)發(fā)一些Java類(lèi)庫(kù)或框架,其中還可以編寫(xiě)一些異常類(lèi)。實(shí)現(xiàn)自定義異常類(lèi)需要繼承Exception類(lèi)或其子類(lèi),如果自定義運(yùn)行時(shí)異常類(lèi)則需繼承RuntimeException類(lèi)或其子類(lèi)?!纠?0.9】實(shí)現(xiàn)自定義異常類(lèi)。示例代碼如

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論