畢業(yè)設(shè)計(論文)-基于java的異常處理技術(shù)及其應(yīng)用_第1頁
已閱讀1頁,還剩26頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、<p><b>  目 錄</b></p><p><b>  一 引言1</b></p><p>  二 關(guān)于JDK和Java異常2</p><p> ?。ㄒ唬㎎ava異常定義2</p><p>  (二)Java中的異常類2</p><p> 

2、 (三)Java語言規(guī)范對異常處理的要求4</p><p>  三 Java異常的處理機制4</p><p> ?。ㄒ唬㎎ava異常處理機制具體實現(xiàn)4</p><p>  (二)Java中異常發(fā)生的原因6</p><p> ?。ㄈ㎎ava異常處理的優(yōu)點6</p><p>  四 Java異常處理技術(shù)及其

3、應(yīng)用8</p><p><b> ?。ㄒ唬伋霎惓?</b></p><p><b> ?。ǘ┎东@異常8</b></p><p><b> ?。ㄈ┒褩?</b></p><p> ?。ㄋ模┳远x異常11</p><p> ?。ㄎ澹╆P(guān)于圖形

4、界面程序的異常捕獲12</p><p>  五 Java異常處理基本原則14</p><p>  (一)不要忽略已檢查型異常14</p><p>  (二)不要一次捕獲所有的異常15</p><p>  (三)使用finally塊釋放資源16</p><p>  (四)異常不能影響對象的狀態(tài)17</

5、p><p>  (五)注意丟失(或忽略)的異常17</p><p>  (六)不要同時使用異常機制和返回值來處理異常20</p><p>  (七)不要讓try塊過于龐大21</p><p><b>  六 結(jié)束語21</b></p><p><b>  致謝21</b&g

6、t;</p><p><b>  參考文獻22</b></p><p><b>  附錄、源代碼22</b></p><p>  基于Java的異常處理技術(shù)及其應(yīng)用</p><p>  摘 要 本文以Java軟件開發(fā)工具箱JDK1.5.0作為環(huán)境,通過與一些編程語言的錯誤處理相比較,介紹了J

7、ava中異常處理技術(shù)的由來、定義、規(guī)范和Java內(nèi)建的異常類,討論了Java中異常產(chǎn)生的原因、實現(xiàn),還對Java異常處理機制的優(yōu)點進行了簡述,就Java異常處理技術(shù)從拋出異常、捕獲異常、堆棧幀、自定義異常、圖形界面程序異常捕獲五個方面進行了討論。本文還就Java異常處理技術(shù)的應(yīng)用做了一些探討,試圖從軟件開發(fā)者的角度說明Java異常處理技術(shù)在開發(fā)中一些有價值的應(yīng)用。</p><p>  關(guān)鍵詞 Java語言 J

8、ava異常處理 JVM </p><p><b>  一 引言</b></p><p>  在程序設(shè)計中,盡管編寫檢查和處理錯誤的程序代碼很乏味,并且它們使程序源代碼顯得冗長,但是,錯誤檢測和處理仍是任何健壯應(yīng)用程序最重要的組成部分之一。傳統(tǒng)的異常處理多采用返回值來標識程序中出現(xiàn)的異常情況,這是程序員熟悉的一種方式,但卻有很多缺點。首先,一個API(Appli

9、cation Programming Interface 應(yīng)用編程接口)可以返回任意的返回值,而這些返回值本身并不能解釋是否代表一個異常情況發(fā)生或者發(fā)生異常的具體情況,需要調(diào)用API的程序自己判斷并解釋返回值的含義。其次,它并沒有一種機制來保證異常情況一定會得到處理,調(diào)用程序可以簡單地忽略該返回值,從而需要調(diào)用API的程序員記住去檢測返回值并處理異常情況。這種方式還讓程序代碼變得晦澀冗長, 當(dāng)進行容易出現(xiàn)異常情況的處理時,比如:I/O操

10、作,程序中會出現(xiàn)很大的部分用于處理異常情況的switch分支,程序代碼的可讀性變得很差。</p><p>  相對于傳統(tǒng)異常處理方式的缺點,Java異常處理機制提供了很好的解決方案。Java異常處理使開發(fā)人員不用編寫特殊代碼檢測返回值就能夠很容易地檢測錯誤,并且把異常處理代碼和異常產(chǎn)生代碼明確地分開,通過拋出Java預(yù)定義或者自定義的異常,能夠表明程序中出現(xiàn)了什么樣的異常情況[1];而且Java的語言機制保證了異

11、常一定會得到恰當(dāng)?shù)奶幚?,合理地使用異常處理機制,會讓程序代碼更清晰。 </p><p>  二 關(guān)于JDK和Java異常</p><p> ?。ㄒ唬㎎ava異常定義 </p><p>  早期的編程語言(比如C語言)沒有異常處理,通常是遇到錯誤返回一個特殊的值或設(shè)定一個標志,并以此判斷是不是有錯誤產(chǎn)生。隨著系統(tǒng)規(guī)模的不斷擴大,這種錯誤處理已經(jīng)成為創(chuàng)建大型可維護程序

12、的障礙了。于是在一些語言中出現(xiàn)了異常處理機制,比如在Basic中的異常處理語句“on error goto”,而Java則是在C++基礎(chǔ)上建立了新的異常處理機制。</p><p>  Java通過面向?qū)ο蟮姆椒ㄟM行異常處理,把各種不同的異常進行分類,并提供了良好的接口。這種機制為復(fù)雜程序提供了強有力的控制方式。同時這些異常代碼與“常規(guī)”代碼分離,增強了程序的可讀性,編寫程序時也顯得更靈活。 在編譯時沒有問

13、題的Java源程序,在運行期可能還會發(fā)生錯誤,這種錯誤就稱為異常(Exception)。異常也可認為是程序運行過程中違背正常指令流而產(chǎn)生的事件[2]。</p><p>  (二)Java中的異常類</p><p>  在Java中,所有的異常都是以類對象的形式存在的。每個異常都是Throwable類或其子類的實例。當(dāng)一個方法出現(xiàn)異常后便拋出一個異常對象,該對象中包含有異常信息,調(diào)用這個對象

14、的方法可以捕獲到這個異常并進行處理[3]。</p><p>  Throwable是所有異常的基類,程序中一般不會直接拋出Throwable對象,Exception和Error是Throwable的子類,Exception下面又有RuntimeException和一般的Exception兩類??梢园袹ava異常分為三類:</p><p>  第一類是Error,Error表示程序在運行期間

15、出現(xiàn)了十分嚴重、不可恢復(fù)的錯誤,在這種情況下應(yīng)用程序只能終止運行,例如Java虛擬機(JVM)出現(xiàn)錯誤。在EJB(Enterprise JavaBean)中將此類歸為JVM 異常,這種類型的異常由 JVM 拋出。Error是一種uncheckedException(未檢查型異常),編譯器不會檢查Error是否被處理,在程序中不用捕獲Error類型的異常;一般情況下,在程序中也不應(yīng)該拋出Error類型的異常。</p><

16、;p>  第二類是RuntimeException,在EJB也稱為系統(tǒng)異常。RuntimeException是一種未檢查型異常,即表示編譯器不會檢查程序是否對RuntimeException作了處理,在程序中不必捕獲未檢查型異常,也不必在方法體聲明拋出RuntimeException類。RuntimeException發(fā)生的時候,表示程序中出現(xiàn)了編程錯誤,所以應(yīng)該找出錯誤修改程序,而不是去捕獲RuntimeException。&l

17、t;/p><p><b>  ……</b></p><p>  …… …… </p><p>  圖2-1 Java異常類層次圖</p><p>  第三類是一般的checkedException, 即已檢查型異常。在EJB中稱為應(yīng)用程序異常。已檢查型異常是在編程中使用最多的異常,所

18、有繼承自Exception并且不是RuntimeException的異常都是已檢查型異常,如圖2-1中為Java異常的類層次圖。</p><p>  Java系統(tǒng)包java.lang、java.util、java.io和java.net中都聲明有標準異常類。這些異常類以未檢查型異常類和已檢查型異常類可分為如下:</p><p>  已檢查型異常類主要有:</p><p&

19、gt;  (1)在java.lang中:</p><p>  ClassNotFoundException:指定名字的類或接口沒有被發(fā)現(xiàn)。</p><p>  CloneNotSupportedException:克隆一個沒有實現(xiàn)Cloneable接口的類。</p><p>  IllegalAccessException:試圖使用給出了完全路徑信息的字符串加載一個

20、類,但當(dāng)前正在執(zhí)行的方法無法訪問指定的類,原因是該類不是public類或是在另一個包中。</p><p>  InstantiationException:試圖使用Class的newInstance方法創(chuàng)建一個對象實例,但是,指定的對象沒有被實例化,因為它是一個接口、抽象類或者一個數(shù)組。</p><p>  InterruptedException:當(dāng)前的線程正在等待,而另一個線程則使用了

21、Thread的interrupt方法中斷了當(dāng)前線程。</p><p> ?。?)在Java.io中:</p><p>  IOException:申請I/O操作沒有成功。</p><p>  EOFException:在輸入操作正常結(jié)束前遇到了文件結(jié)束符。</p><p>  FileNotFoundException:在文件系統(tǒng)中,沒有找到

22、由文件名字符串指定的文件。</p><p>  InterruptedIOException當(dāng)前線程正在等待I/O操作的完成,而另一個線程使用thread的interrupt方法中斷了當(dāng)前線程。</p><p>  未檢查型異常類主要有:</p><p>  (1)在java.lang中:</p><p>  ArithmeticExcept

23、ion:表示遇到了算術(shù)的異常問題,例如0作為除數(shù)。</p><p>  ArrayStoreException:試圖把與數(shù)組類型不相符的值存入數(shù)組。</p><p>  ClassCastException:試圖把一個對象的引用強制轉(zhuǎn)換為不合適的類型。</p><p>  InderOutOfBoundsException:數(shù)組的下標越界。</p>&

24、lt;p>  NullPointerException:試圖使用一個空的對象引用。</p><p>  SecurityException:檢測到了違反安全的行為。</p><p> ?。?)在java.util中:</p><p>  EmptyStaceException:試圖訪問一個空堆棧中的一個元素。</p><p>  NoS

25、uchElementException:試圖訪問一個空向量中的元素。</p><p> ?。ㄈ㎎ava語言規(guī)范對異常處理的要求</p><p>  Java語言規(guī)定必須對已檢查型異常作處理,編譯器會對此作檢查,要么在方法體中聲明拋出已檢查型異常,要么使用catch語句捕獲已檢查型異常進行處理,不然不能通過編譯[2]。已檢查型異常用于以下環(huán)境:</p><p>  

26、(1)該異常發(fā)生后是可以被恢復(fù)的,如一個Internet連接發(fā)生異常被終止后,可以重新連接再進行后續(xù)操作。</p><p> ?。?)程序依賴于不可靠的外部條件,該依賴條件可能出錯,如系統(tǒng)I/O。</p><p>  (3)該異常發(fā)生后并不會導(dǎo)致程序處理錯誤,進行一些處理后可以繼續(xù)后續(xù)操作。</p><p>  Java語言規(guī)范中將任何Error的子類以及Runti

27、meException的子類都稱為未檢查型異常。而其它異常都稱為已檢查型異常。</p><p>  三 Java異常的處理機制</p><p> ?。ㄒ唬㎎ava異常處理機制具體實現(xiàn)</p><p>  在Java程序運行出現(xiàn)異常時,發(fā)生異常的程序段要拋出異常,而運行系統(tǒng)負責(zé)尋找一段代碼來處理異常。Java語言中,創(chuàng)建一個異常對象并將它交給運行系統(tǒng)稱為拋出一個異常

28、,又稱為異常拋出。</p><p>  在Java中,一個方法要拋出異常,必須遵循一定的規(guī)定,即所謂的“異常規(guī)范”。異常規(guī)范采用了一個額外的關(guān)鍵字:throws。要使方法拋出異常,應(yīng)在方法聲明中,位于參變量列表的后面(即throws后面)列舉全部潛在的異常類型。</p><p>  假若Java中的某方法可能拋出一個異常,但程序中沒有對其進行控制,編譯器會偵測到這個情況,通知程序員必須在此

29、方法內(nèi)進行異??刂?或者從方法里拋出一個異常。通過遵守異常規(guī)范,Java可在編譯期保證異常處理的正確性。</p><p>  當(dāng)Java拋出一個異常,程序?qū)膶?dǎo)致異常的代碼處跳出,JVM檢測尋找和try關(guān)鍵字匹配的處理該異常的catch塊,如果找到,將控制權(quán)交到catch塊中的代碼,然后繼續(xù)往下執(zhí)行程序, 如果沒有找到處理該異常的catch塊,try塊中發(fā)生異常的代碼不會被重新執(zhí)行,在所有的finally塊代碼被

30、執(zhí)行和當(dāng)前線程的所屬的ThreadGroup的uncaughtException方法被調(diào)用后,遇到異常的當(dāng)前線程被終止。</p><p>  Java異常處理的語句形式如下:</p><p><b>  try</b></p><p><b>  {</b></p><p>  //正常執(zhí)行的代碼可

31、能產(chǎn)生異常</p><p>  throw(異常類1 e,異常類2 e,……異常類n e)</p><p><b>  }</b></p><p>  catch(異常類1 e)</p><p><b>  {</b></p><p>  //異常類1的處理代碼</p&

32、gt;<p><b>  }</b></p><p>  catch(異常類2 e)</p><p><b>  {</b></p><p>  //異常類2的處理代碼</p><p><b>  }</b></p><p><b&g

33、t;  ……</b></p><p>  catch(異常類n e)</p><p><b>  {</b></p><p>  //異常類n的處理代碼</p><p><b>  finally</b></p><p><b>  {</b>

34、;</p><p>  //執(zhí)行清除工作的語句</p><p><b>  }</b></p><p>  Java程序運行在try塊中,如果產(chǎn)生了異常,則不再運行try塊下面的語句,而直接進入catch塊中,尋找第一個與之匹配的異常類型。try/catch語句會自動在try塊后面的各個catch塊中,找出與該異常類相匹配的參數(shù)。如果該參數(shù)符合

35、以下三個條件之一時,則認為這個參數(shù)與產(chǎn)生的異常相匹配[4]。</p><p>  (1)參數(shù)與產(chǎn)生的異常屬于同一個類。</p><p>  (2)參數(shù)是產(chǎn)生異常的父類。</p><p>  (3)參數(shù)是一個接口,產(chǎn)生的異常實現(xiàn)了這一個接口。</p><p>  當(dāng)產(chǎn)生的異常找到了第一個與之相匹配的參數(shù)時,就執(zhí)行這一參數(shù)的catch塊中的Jav

36、a代碼。執(zhí)行完catch塊后,程序恢復(fù)執(zhí)行,但不會回到異常發(fā)生處繼續(xù)執(zhí)行而是執(zhí)行try/catch結(jié)構(gòu)后面的代碼。</p><p>  finally語句可以說是為異常處理事件提供的一個清理機構(gòu)。一般是用來關(guān)閉文件或者釋放其他的系統(tǒng)資源作為try/catch/finally結(jié)構(gòu)的一部分,可以沒有finally塊。如果存在finally塊,無論try塊中是否發(fā)生異常,是否執(zhí)行過catch塊,都要執(zhí)行finally塊

37、。用finally塊的一個好處,就是把方法中所有清除狀態(tài)和關(guān)閉系統(tǒng)文件的語句放在一起,不但避免代碼的重復(fù),更是減少出現(xiàn)遺漏語句,對于程序以后的修改也較為集中和方便。</p><p> ?。ǘ㎎ava中異常發(fā)生的原因</p><p>  異常發(fā)生有三種原因:</p><p> ?。?)Java虛擬機檢測到了非正常的執(zhí)行狀態(tài),這些狀態(tài)可能由三種因素之一引起:</

38、p><p> ?、俦磉_式的計算違背了Java語言的語義,例如:數(shù)組越界、除數(shù)為0等。</p><p> ?、谠谳d入和鏈接Java程序時出現(xiàn)錯誤。</p><p> ?、鄢隽讼到y(tǒng)的資源限制,例如使用了太多的內(nèi)存這些無法預(yù)知的異常。</p><p> ?。?)Java程序代碼中的throw語句被執(zhí)行。</p><p> ?。?/p>

39、3)發(fā)生異步異常,其可能的原因有Thread類的stop方法被調(diào)用;JVM內(nèi)部發(fā)生錯誤;運行時庫出現(xiàn)了內(nèi)部錯誤等。</p><p> ?。ㄈ㎎ava異常處理的優(yōu)點</p><p>  在面向過程的傳統(tǒng)語言中對程序中可能出現(xiàn)的錯誤一般采取:查錯、報錯和排錯的處理錯誤代碼和常規(guī)代碼混雜在一起的方法。比如在C語言(面向過程的一種編程語言)中輸出流的處理偽代碼是:</p><

40、p>  {建立一個文件輸入流;</p><p>  if(建立不成功){ 報錯;處理錯誤;}</p><p>  else { 從輸入流中讀入一個字符;</p><p>  if(讀入不成功){ 報錯;處理錯誤;關(guān)閉該文件的輸入流</p><p>  if(關(guān)閉不成功) { 報錯;處理錯誤; }</p><p>

41、  else { …… }</p><p><b>  }</b></p><p><b>  else</b></p><p><b>  ……    </b></p><p><b>  }</b></p><p>  經(jīng)過這

42、樣的處理,程序可以保證正常地運行。但是程序的每一步都要考慮是否會發(fā)生錯誤,出現(xiàn)了錯誤又該如何處理的問題。這不但使程序代碼的行數(shù)大大增加,而且,處理錯誤代碼和正常代碼混雜在一起,使程序流程變得十分復(fù)雜,不利于閱讀。此外,它對于同一類型的錯誤也不方便進行統(tǒng)一的處理。</p><p>  于上面等價實現(xiàn)地面向?qū)ο笳Z言處理異常的偽代碼為:</p><p>  try{ 建立一個文件輸入流;<

43、/p><p>  讀取一個字符;......;</p><p><b>  關(guān)閉該輸入流;}</b></p><p>  catch( 文件輸入流打開失敗 ){ 報錯;處理錯誤;......; }</p><p>  catch( 讀入字符失敗 ){ 報錯;處理錯誤;......}</p><p>&

44、lt;b>  ......</b></p><p><b>  }</b></p><p>  面向?qū)ο笳Z言的異常處理對于面向過程語言處理錯誤的方法有三種好處:其一將處理錯誤代碼和正常代碼分離;其二能夠?qū)惓Q刂{(diào)用堆棧向上傳播;其三能按異常類型和異常對象分組。</p><p>  四 Java異常處理技術(shù)及其應(yīng)用</

45、p><p><b> ?。ㄒ唬伋霎惓?lt;/b></p><p>  如果有一個現(xiàn)成(或者已定義)的異??梢允褂?,則拋出異常很容易。只要滿足以下三點:</p><p> ?。?)找到一個恰當(dāng)?shù)漠惓n?lt;/p><p> ?。?)構(gòu)造一個該類的實例</p><p><b>  (3)拋出該實例&l

46、t;/b></p><p>  比如我們經(jīng)常遇到IOException異常發(fā)生,其中它的一個子類是EOFException,就是描述在輸入過程中碰到一個未預(yù)期的文件結(jié)尾標志,我們拋出該異常的方法如下:</p><p>  throw new EOFException ( );</p><p><b>  或者這樣:</b></p

47、><p>  EOFException e = new EOFException ( );</p><p>  throw e ;</p><p><b> ?。ǘ┎东@異常</b></p><p>  要想捕獲一個異常,需要設(shè)置一個try/catch的代碼塊。try塊的最簡單形式如下:</p><

48、p><b>  try {</b></p><p><b>  code</b></p><p><b>  more code</b></p><p><b>  }</b></p><p>  catch (ExceptionType e ) {

49、</p><p>  handler for this type</p><p><b>  }</b></p><p>  如果try塊內(nèi)的任何代碼拋出了由catch塊中指定的異常,則程序跳過try塊中的其它代碼,程序執(zhí)行catch塊中的處理代碼。假如try塊沒有任何代碼拋出異常,那么程序會直接跳過catch塊的內(nèi)容。當(dāng)然,可以在try塊同時

50、捕獲多個異常,并分別對每種類型加以不同的處理。</p><p><b>  (三)堆棧幀</b></p><p>  在JDK1.4前,通過使用Throwable類的printStacktrace方法來獲得堆棧結(jié)構(gòu)的文本描敘。現(xiàn)在,可以通過調(diào)用getStackTrace方法來獲得一個StackTraceElement對象的數(shù)組,通過研究該數(shù)組,就可以分析程序運行情況。

51、例如:</p><p>  Throwable t = new Throwable ( );</p><p>  StackTraceElement[ ] frames = t.getStackTrace ( );</p><p>  For ( int i= 0;i<frames.length;i++) </p><p>  使用St

52、ackTraceElement類提供的方法獲取文件名以及當(dāng)前執(zhí)行的代碼行行號的方法,同樣,它還提供獲取類名、方法名的方法。而toString方法可以產(chǎn)生一個格式化字符串,其中包含那些獲得的信息。</p><p>  以下程序StackTest.java輸出一個遞歸調(diào)用方法的堆棧情況。</p><p>  import java.util.*;</p><p>  

53、import javax.swing.*;</p><p>  public class StackTest</p><p><b>  {</b></p><p>  /** 返回 n! = 1 * 2 * . . . * n 的結(jié)果 */</p><p>  public static in

54、t factorial (int n)</p><p><b>  {</b></p><p>  System.out.println ("factorial (" + n + "):" ) ;</p><p>  Throwable t = new Throwable( );</p>

55、<p>  StackTraceElement[ ] frames = t.getStackTrace();</p><p>  for ( int i = 0 ;i < frames.length; i++ )</p><p>  System.out.println( frames[ i] );</p><p><b>  int

56、r ;</b></p><p>  if (n <= 1) r = 1;</p><p>  else r = n * factorial(n - 1); // 遞歸調(diào)用factorial()方法</p><p>  System.out.println("return " + r);</p><p>

57、;<b>  return r;</b></p><p><b>  }</b></p><p>  public static void main(String[] args)</p><p><b>  {</b></p><p>  String input = JOpt

58、ionPane.showInputDialog( "請輸入一個整數(shù):" );</p><p>  int n =Integer.parseInt(input);</p><p>  factorial(n);</p><p>  System.exit( 0 ); //退出程序</p><p>

59、;<b>  }</b></p><p><b>  }</b></p><p>  由于需要從標準輸入中獲取整數(shù)數(shù)字,Integer.ParseInt(input)方法可能會產(chǎn)生java.lang.NumberFormatException異常。運行程序時界面:</p><p>  圖3-1 輸入界面</p>

60、;<p>  如果我們要實現(xiàn)遞歸方法factorial(3),通過getStackTrace方法可以查看程序運行的過程。其結(jié)果為如下:</p><p>  圖3-2 遞歸方法factorial(3)的輸出結(jié)果</p><p>  而這個程序可能產(chǎn)生的一個異常是NumberFormatException異常。當(dāng)異常產(chǎn)生后,JVM調(diào)用該異常處理。其運行界面如下:</p

61、><p>  圖3-3 輸入一個產(chǎn)生異常的數(shù)據(jù)</p><p>  返回到控制臺的結(jié)果為描述該異常:</p><p>  圖3-4 輸入異常數(shù)據(jù)時在控制臺產(chǎn)生的結(jié)果</p><p><b> ?。ㄋ模┳远x異常</b></p><p>  由于在Java中,異常也被看成是對象,而且異常和一

62、般的對象沒有什么不同。因此,任何類都可以定義它自己的異常,并用throw語句引發(fā)它們。其中,throw語句由帶有一個對象的關(guān)鍵字throw組成,這個對象應(yīng)該是Exception或其子類的一個實體對象。要注意的是,當(dāng)執(zhí)行了一條throw語句后,就不會執(zhí)行該語句之后的任何代碼了。</p><p>  通常每個異常類提供一個默認的構(gòu)造器以及一個包含詳細信息的構(gòu)造器。使用Throwable的toString方法會輸出該詳

63、細信息,這個方法對代碼調(diào)試是很有用處。</p><p>  例如創(chuàng)建這樣的異常類:</p><p>  class FileFormatException extends IOException {</p><p>  public FileFormatException ( ) { </p><p><b>  }<

64、;/b></p><p>  public FileFormatException ( ) {</p><p>  super ( gripe) ;</p><p><b>  }</b></p><p><b>  }</b></p><p>  String re

65、adData ( BufferedReader in ) throws FileFormatException {</p><p><b>  ……</b></p><p>  while ( ……)</p><p><b>  {</b></p><p>  if ( ch==-1) /

66、/EOF標記,即文件結(jié)尾</p><p><b>  {</b></p><p>  if (n<len) </p><p>  throw new FileFormatException ( );</p><p>  //拋出自定義的異常類FileFormatException</p><

67、p><b>  }</b></p><p><b>  ……</b></p><p><b>  }</b></p><p><b>  return s;</b></p><p><b>  } </b></p>

68、;<p> ?。ㄎ澹╆P(guān)于圖形界面程序的異常捕獲</p><p>  對于一個非圖形界面的程序而言,如果一個異常沒有被捕獲,則程序會終止運行并且在控制臺輸出一條包含異常類型以及堆棧內(nèi)容的信息。而對于具有圖形界面的程序(包含applet以及應(yīng)用程序),也會輸出這些錯誤信息,但是程序會返回用戶界面外層循環(huán)中去。</p><p>  下面我們從一個有趣的程序-顏色調(diào)和板來討論圖形界面

69、程序處理異常的情況。</p><p>  在SwingColorTest.java(源代碼見附錄)中,程序可以根據(jù)我們輸入紅色、綠色、藍色(RGB)、亮度、飽和度和色度值來調(diào)節(jié)顏色。整個程序除了可能會產(chǎn)生RuntimeException異常外,這個程序還會產(chǎn)生NumberFormatException異常。當(dāng)然這是已檢查型異常。</p><p>  下面我們來看它在JVM中的運行情況:&l

70、t;/p><p>  圖4-1 輸入正常數(shù)據(jù)時的顏色調(diào)和板</p><p>  當(dāng)我們改變”紅色”值為非法的一個輸入,比如:“AB”時,其運行結(jié)果為如下:</p><p>  圖4-2 輸入一個產(chǎn)生異常的數(shù)據(jù)</p><p>  顏色未變化,好像程序發(fā)生邏輯錯誤似的(沒有按照我們希望的去運行)其實程序已將控制權(quán)轉(zhuǎn)到控制中心去了,這個圖形還處于

71、初始化階段(在輸入“AB”前)。在控制中心我們發(fā)現(xiàn)如下一些異常發(fā)生描述:</p><p>  圖4-3 異常產(chǎn)生后返回到控制臺的說明</p><p>  這說明發(fā)生了NumberFormatException(數(shù)字格式異常)異常后,并沒有繼續(xù)往下執(zhí)行代碼。由于數(shù)字格式異常為已檢查型異常,直接調(diào)用系統(tǒng)的方法處理了。</p><p>  JVM報告程序發(fā)生了數(shù)字格式異

72、常產(chǎn)生,并將其具體的情況報告給用戶。但是,是不是這個程序不能再接受正常的輸入數(shù)據(jù)運行呢?還是必須要重新啟動才能運行?</p><p>  我們將“紅色”值由“AB”改為“200”后發(fā)現(xiàn)顏色改變,這說明該程序還能運行。結(jié)果如下圖:</p><p>  圖4-4 將產(chǎn)生異常的輸入數(shù)據(jù)更改后的顏色調(diào)和板</p><p>  可見當(dāng)輸入了正常的數(shù)據(jù)后,程序就像第一次運行一

73、樣,可以正確的顯示顏色了。我們得到的結(jié)論是:部分Java圖形界面程序發(fā)生異常后不需要重新初始化,依舊可以運行,但必須不再有異常發(fā)生。</p><p>  五 Java異常處理基本原則</p><p>  合理使用Java異常機制可以使程序健壯而清晰,但是,Java異常處理機制也常常會被錯誤地使用,下面就討論一些關(guān)于使用異常的原則:</p><p>  (一)不要忽

74、略已檢查型異常</p><p><b>  注意下面的代碼:</b></p><p><b>  try {</b></p><p>  method1(); //method1拋出Exception A</p><p><b>  }</b><

75、;/p><p>  catch(Exception A) //捕獲Exception A</p><p><b>  {</b></p><p>  e.rintStackTrace( ); //打印捕獲異常</p><p><b>  }</b></p>

76、<p>  上面的代碼似乎沒有什么問題,捕獲異常后將異常打印,然后繼續(xù)執(zhí)行。事實上在catch塊中對發(fā)生的異常情況并沒有作任何處理。雖然程序能夠繼續(xù)執(zhí)行,但是由于這里的操作已經(jīng)發(fā)生異常,將會導(dǎo)致以后的操作不能按照預(yù)期的情況發(fā)展下去,可能導(dǎo)致兩個結(jié)果。</p><p>  一種情況是這里的異常導(dǎo)致在程序中別的地方拋出一個異常,這會使程序員在調(diào)試時感到迷惑,因為新的異常拋出的地方并不是程序真正發(fā)生問題的地方

77、,也不是發(fā)生問題的真正原因。</p><p>  另外一種情況程序繼續(xù)運行,并得出一個錯誤的輸出結(jié)果,這種問題更加難以捕捉,因為很可能把它當(dāng)成一個正確的輸出。</p><p>  那么應(yīng)該如何處理呢?一般有四個選擇:處理異常,進行修復(fù)以讓程序繼續(xù)執(zhí)行;重新拋出異常,在對異常進行分析后發(fā)現(xiàn)這里不能處理它,那么重新拋出異常,讓調(diào)用者處理;將異常轉(zhuǎn)換為用戶可以理解的自定義異常再拋出,這時應(yīng)該注意

78、不要丟失原始異常信息;不要捕獲異常。</p><p>  因此,當(dāng)捕獲一個未檢查型異常時,必須對異常進行處理;如果認為不必要在這里作處理,就不要捕獲該異常,在方法體中聲明方法拋出異常,由上層調(diào)用者來處理該異常。</p><p>  (二)不要一次捕獲所有的異常</p><p>  我們常見如下關(guān)于異常處理的代碼:</p><p><b&

79、gt;  try</b></p><p><b>  {</b></p><p>  method1(); //method1拋出ExceptionA</p><p>  method2(); //method2拋出ExceptionB</p><p

80、>  method3(); //method3拋出ExceptionC</p><p><b>  }</b></p><p>  catch(Exception e) //捕獲所有異常</p><p><b>  { …… }</b></p><p

81、>  代碼中使用一個catch子句捕獲了所有異常,看上去很簡潔,一個代碼段就捕獲了全部的異常。但是這里有兩個潛在的缺陷,一是對try塊中拋出的每種異常,很可能需要不同的處理和恢復(fù)措施,而由于這里只有一個catch塊,分別處理就不能實現(xiàn)。二是try塊中還可能拋出RuntimeException,代碼中捕獲了所有可能拋出的RuntimeException而沒有作任何處理,掩蓋了編程的錯誤,會導(dǎo)致程序難以調(diào)試。</p>&

82、lt;p>  我們應(yīng)該處理為以下的代碼:</p><p><b>  try</b></p><p><b>  {</b></p><p>  method1();</p><p>  method2();</p><p>  method3();

83、</p><p><b>  }</b></p><p>  catch (ExceptionA e)//分別捕獲和處理三種異常</p><p><b>  { …… }</b></p><p>  catch (ExceptionB e)</p><p><

84、b>  { …… }</b></p><p>  catch (ExceptionC e)</p><p><b>  { …… }</b></p><p>  (三)使用finally塊釋放資源</p><p>  關(guān)鍵字finally保證程序使用任何方式離開try塊,finally塊中的語句都會被執(zhí)

85、行。當(dāng)程序中使用了外界資源,如數(shù)據(jù)庫連接、文件等,將釋放這些資源的代碼寫入finally塊中是很好的處理方式。</p><p>  必須注意的是,在finally塊中不能拋出異常。Java異常處理機制保證在任何情況下必須先執(zhí)行finally塊然后再離開try塊,因此在try塊中發(fā)生異常的時候,Java虛擬機先轉(zhuǎn)到finally塊執(zhí)行finally塊中的代碼,finally塊執(zhí)行完畢后,再向外拋出異常。如果在fin

86、ally塊中拋出異常,try塊捕捉的異常就不能拋出,外部捕捉到的異常就是finally塊中的異常信息,而try塊中發(fā)生的真正的異常堆棧信息則丟失了。</p><p>  Connectioncon = null;</p><p><b>  try {</b></p><p>  con=dataSource.getConnection();&

87、lt;/p><p><b>  //拋出數(shù)據(jù)庫異常</b></p><p><b>  }</b></p><p>  catch(SQLException e ) {</p><p><b>  ……</b></p><p>  //捕獲異常進行一些處理后

88、再將數(shù)據(jù)庫異常拋出給調(diào)用者處理</p><p><b>  throw e;</b></p><p><b>  }</b></p><p><b>  finally {</b></p><p><b>  try {</b></p>&l

89、t;p>  con.close();</p><p><b>  }</b></p><p>  catch(SQLException e) {</p><p>  e.printStackTrace();</p><p><b>  ……</b></p><p>&l

90、t;b>  }</b></p><p><b>  }</b></p><p>  由于con為null,finally塊有異常發(fā)生,從而使try塊中發(fā)生的異常堆棧信息丟失。其調(diào)用者會得到如下信息:</p><p>  Java.lang.NullPointerExceptionat</p><p> 

91、 myPackage.MyClass.method1(methodl.Java:266)</p><p>  (四)異常不能影響對象的狀態(tài)</p><p>  異常產(chǎn)生后不能影響對象的狀態(tài),這是異常處理中的一條重要規(guī)則。一個函數(shù)中發(fā)生異常后,對象的狀態(tài)應(yīng)該和調(diào)用這個函數(shù)之前保持一致,以確保對象處于正確的狀態(tài)中。</p><p>  如果對象是不可變對象(指調(diào)用構(gòu)造函

92、數(shù)創(chuàng)建后就不能改變的對象),即創(chuàng)建后沒有任何方法可以改變對象的狀態(tài),那么異常發(fā)生后對象狀態(tài)肯定不會改變。如果是可變對象,必須在編程中注意保證異常不會影響對象狀態(tài)。</p><p>  有三個方法可以做到異常不能影響對象地狀態(tài):</p><p> ?。?)將可能產(chǎn)生異常的代碼和改變對象狀態(tài)的代碼分開,先執(zhí)行可能產(chǎn)生異常的代碼,如果產(chǎn)生異常,就不執(zhí)行改變對象狀態(tài)的代碼。</p>

93、<p> ?。?)對不容易分離產(chǎn)生異常代碼和改變對象狀態(tài)代碼的方法,定義一個recover方法,在異常產(chǎn)生后調(diào)用recover方法修復(fù)被改變的類變量,恢復(fù)方法調(diào)用前的類狀態(tài)。</p><p>  (3)在方法中使用對象的拷貝,這樣當(dāng)異常發(fā)生后,被影響的只是拷貝,對象本身不會受到影響。</p><p>  (五)注意丟失(或忽略)的異常</p><p>  

94、在程序設(shè)計中,可以丟失(忽略)一些異常,但是為了以后更好地維護代碼,最好不要丟失異常。比如下面的代碼:</p><p>  public void method2( ) {</p><p><b>  try</b></p><p><b>  {</b></p><p><b>  …

95、…</b></p><p>  method1( ); //method1進行了數(shù)據(jù)庫操作</p><p><b>  }</b></p><p>  catch( SQLException e )</p><p><b>  {</b></p>

96、<p><b>  ……</b></p><p>  //捕獲數(shù)據(jù)庫異常后將該異常封裝為</p><p>  //MyException后重新拋出</p><p>  throw new MyException(“發(fā)生了數(shù)據(jù)庫異常:" +e.getMessage);</p><p><b

97、>  }</b></p><p><b>  }</b></p><p>  public void method3( ) {</p><p><b>  try</b></p><p><b>  {</b></p><p>  

98、method2( ); //調(diào)用method2(),拋出MyException</p><p>  catch (MyException e)</p><p><b>  {</b></p><p>  e.printStackTrace( );</p><p><b>  ……

99、</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  在method2的代碼中,try塊捕獲method1拋出的數(shù)據(jù)庫異常SQLException后,拋出了新的自定義異常MyException。這段代碼是似乎沒有什么問題,但在控制臺的輸出卻是:</p

100、><p>  MyException:發(fā)生了數(shù)據(jù)庫異常:對象名稱“MyTable"無效</p><p>  atMyClass.method2(MyClass.Java:232)</p><p>  atMyClass.method3(MyClass.Java:255)</p><p>  原始異常SQLException的信息丟失了,

101、這里只能看到method2里面定義的MyException的堆棧情況,而method1中發(fā)生的數(shù)據(jù)庫異常的堆棧則看不到。</p><p>  如何排錯呢?只有在method1的代碼行中一行行去尋找數(shù)據(jù)庫操作語句。JDK的開發(fā)者們也意識到了這個情況,在JDK1.4.1中,Throwable類增加了兩個構(gòu)造方法,public Throwable ( Throwablecause)和public Throwable (

102、 Stringmessage, Throwablecause ),在構(gòu)造函數(shù)中傳入的原始異常堆棧信息將會在printStackTrace方法中打印出來。但在JDK1.3中就只能靠程序員來實現(xiàn)打印原始異常堆棧信息了。實現(xiàn)過程也很簡單,只需要在自定義的異常類中增加一個原始異常字段,在構(gòu)造函數(shù)中傳入原始異常,然后重載printStackTrace方法,首先調(diào)用類中保存的原始異常的printStackTrace方法,然后再調(diào)用super.pri

103、ntStackTrace方法就可以打印出原始異常信息了??梢赃@樣定義前面代碼中出現(xiàn)的MyException類:</p><p>  public class MyException extends Exception</p><p><b>  {</b></p><p>  public SMException ( Throwable ca

104、use )</p><p><b>  //構(gòu)造函數(shù)</b></p><p><b>  {</b></p><p>  this.cause1=cause;</p><p><b>  }</b></p><p>  public MyExceptio

105、n ( Strings ,Throwable cause )</p><p><b>  {</b></p><p><b>  super(s);</b></p><p>  this.cause1=cause;</p><p><b>  }</b></p>

106、<p>  //重載printStackTrace方法,打印出原始異常堆棧信息</p><p>  public void printStackTrace()</p><p><b>  {</b></p><p>  if(cause1!=null)</p><p><b>  {</b

107、></p><p>  cause1.printStackTrace();</p><p><b>  }</b></p><p>  super.printStackTrace(s);</p><p><b>  }</b></p><p>  public voi

108、d printStackTrace(PrintStream s)</p><p><b>  {</b></p><p>  if(cause1!=null)</p><p><b>  {</b></p><p>  cause1.printStackTrace(s);</p>

109、<p><b>  }</b></p><p>  super.printStackTrace(s);</p><p><b>  }</b></p><p>  public void printStackTrace( PrintWriter s )</p><p><b&g

110、t;  {</b></p><p>  if(cause1!=null)</p><p><b>  {</b></p><p>  cause1.printStackTrace(s);</p><p><b>  }</b></p><p>  super.pr

111、intStackTrace(s);</p><p><b>  }</b></p><p>  private Throwable cause1;</p><p><b>  }</b></p><p>  (六)不要同時使用異常機制和返回值來處理異常</p><p>  

112、我們可能會使用類似下面一段代碼:</p><p><b>  try{</b></p><p>  doSomething( );</p><p><b>  }</b></p><p>  catch(MyException e){</p><p>  if(e.getEr

113、rcode==-1)</p><p><b>  { …… }</b></p><p>  if(e.getErrcode==-2)</p><p><b>  { …… }</b></p><p><b>  …… </b></p><p>  假如過

114、一段時間再來閱讀這段代碼,你很難弄明白程序的意思?;旌鲜褂肑ava異常處理機制和返回值使程序的異常處理部分變得混亂,并難以理解。</p><p>  在程序中,如果有多種不同的異常情況,就應(yīng)該定義多種不同的異常,而不要像上面代碼那樣。綜合使用Exception和返回值。處理應(yīng)該如下:</p><p><b>  try {</b></p><p&g

115、t;  doSomething( );</p><p>  //doSomething()拋出MyExceptionA和MyExceptionB</p><p><b>  }</b></p><p>  catch(MyExceptionA e) //捕獲異常分別進行處理</p><p><b> 

116、 { …… }</b></p><p>  catch(MyExceptionB e)</p><p><b>  { …… }</b></p><p>  (七)不要讓try塊過于龐大</p><p>  有人習(xí)慣用一個龐大的try塊包含所有可能產(chǎn)生異常的代碼,這樣有兩個壞處:一是閱讀代碼的時候,在try塊

117、冗長的代碼中,不容易知道到底是哪些代碼會拋出哪些異常,不利于代碼維護;二是使用try捕獲異常是以程序執(zhí)行效率為代價的,將不需要捕獲異常的代碼包含在try塊中,影響了代碼執(zhí)行的效率。因此,在Java程序中最好將try塊編寫得簡潔些。</p><p><b>  六 結(jié)束語</b></p><p>  Java是一種面向?qū)ο蟮某绦蛟O(shè)計語言,Java的異常處理機制非常出色

118、。Java中的所有異常都是從基礎(chǔ)類Throwable里繼承而來的,所以可確保我們得到的是一個通用接口。丟棄一個錯誤的異常后,Java異常規(guī)范是在編譯期間檢查并執(zhí)行的。被取代的方法必須遵守那一方法的基礎(chǔ)類的異常規(guī)范。</p><p>  Java可丟棄指定的異常或者從指定異常衍生出來的其他異常。這樣一來,運用try/catch/finally異常處理機制,最終得到的是更為“健壯”的異常控制代碼。Java異常處理為大

119、的程序項目帶來很好的健壯性。</p><p>  當(dāng)然,在寫本論文時,由于對Java的學(xué)習(xí)沒達到深入、精通程度,掌握Java異常處理技術(shù)也不是很全面,故而論文中對Java圖形程序的異常處理方面和Java異常處理機制具體實現(xiàn)的討論仍有不足之處有待以后改進。</p><p><b>  致謝</b></p><p><b>  參考文獻&

120、lt;/b></p><p>  [1]Bloch J.Effective. Java Programming Language Guide.北京:機械工業(yè)出版社,2001.</p><p>  [2]Cay S.Horstmann .Core Java 2(第6版) .北京:機械工業(yè)出版社,2004.</p><p>  [3]Rogers Cadenhea

121、d ,Laura Lemay.Teach Yourself Java 2 In 21`days.北京:人民郵電出版社,2004.</p><p>  [4]朱福喜,唐曉軍.Java程序設(shè)計技巧與實例.北京:人民郵電出版社,2004.</p><p>  [5]譚浩強,程龍,楊海蘭,吳功宜.Java編程技術(shù).北京:人民郵電出版社,2003.</p><p>  [6]

122、彭晨陽.Java實用系統(tǒng)開發(fā)指南. 北京:機械工業(yè)出版社,2003.</p><p>  [7]Java 2 SDK1.5.0 Standard Edition Documentation</p><p>  [8]http://Java.sun.com/j2se/index.jsp</p><p>  [9]黃聰明.精通Java 2 程序設(shè)計.北京:清華大學(xué)出版社

123、,2004.</p><p>  [10]Kalthy Sierra,Bert Bates.Java 2學(xué)習(xí)指南.北京:人民郵電出版社,2004.</p><p>  [11]耿祥義.Java基礎(chǔ)教程.北京:清華大學(xué)出版社,2004.</p><p>  [12]朱福喜.Java程序設(shè)計技巧與開發(fā)實例.北京:人民郵電出版社,2004.</p><

124、p>  [13]謝小樂.J2EE經(jīng)典實例詳解.北京:人民郵電出版社,2003.</p><p>  [14]Y.Daniel Liang.Java語言程序設(shè)計(第三版).北京:機械工業(yè)出版社,2005. </p><p>  [15]Bruce Eckel.Java編程思想. 北京:機械工業(yè)出版社,2005.</p><p><b>  附

溫馨提示

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

評論

0/150

提交評論