小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

有關(guān)JAVA異常和錯(cuò)誤(ERROR)的處理

 暗夜魅影 2012-01-02

有關(guān)JAVA異常和錯(cuò)誤(ERROR)的處理

最近遇到有關(guān)ERROR的處理問(wèn)題,下面這篇文章

 轉(zhuǎn)至:http://www.cnblogs.com/deepnighttwo/archive/2006/12/11/1964305.html

 LinkageError是一個(gè)比較棘手的異常,準(zhǔn)確的說(shuō)它是一個(gè)Error而不是Exception。java api對(duì)它沒(méi)有直接的解釋?zhuān)墙榻B了它的子類(lèi):

    Subclasses of LinkageError indicate that a class has some dependency on another class; however, the latter class has incompatibly changed after the compilation of the former class.

似乎是說(shuō)不兼容性,既編譯時(shí),A類(lèi)用到B類(lèi),且這時(shí)候A和B是兼容的,但是到運(yùn)行時(shí),A類(lèi)得到的B(既某個(gè)類(lèi)加載器加載的B類(lèi))卻不是A在編譯的時(shí)候那個(gè)與之兼容的B,這個(gè)說(shuō)起來(lái)比較復(fù)雜,其實(shí)就是個(gè)二進(jìn)制兼容性問(wèn)題,和很多程序不能在98上跑是一個(gè)道理,程序就是A,而98就是B。
事實(shí)上,真正出現(xiàn)二進(jìn)制兼容性問(wèn)題的時(shí)候,確實(shí)是報(bào)NoSuchMethodError或者NoSuchFieldError或者NoClassDefFoundError。Java api對(duì)NoSuchMethodError的解釋(其他的解釋幾乎相同):
Thrown if an application tries to call a specified method of a class (either static or instance), and that class no longer has a definition of that method.
Normally, this error is caught by the compiler; this error can only occur at run time if the definition of a class has incompatibly changed.
 
關(guān)鍵詞是“incompatibly changed ”。
 
事實(shí)證明,當(dāng)傳統(tǒng)意義上的二進(jìn)制不兼容性(既上面舉的98的例子,或者說(shuō)incompatibly changed)問(wèn)題發(fā)生的時(shí)候,java會(huì)報(bào)NoSuchMethodError,NoSuchFieldError或者NoClassDefFoundError ,這三個(gè)類(lèi)都是LinkageError的子類(lèi),所以,就好像java api對(duì)LinkageError中的解釋一樣“Subclasses of LinkageError indicate that……”這個(gè)解釋并沒(méi)有說(shuō)LinkageError本身應(yīng)該是在什么情況下被拋出。倒不是java api顧左右而言他,而是拋出LinkageError的情況實(shí)在是很難敘述,《深入java虛擬機(jī)》第二版用近乎一章(比較大的一章,和其它章相比)來(lái)解釋這個(gè)問(wèn)題。歸根結(jié)底,原因是ClassLoader沒(méi)有完全按照設(shè)計(jì)的那樣設(shè)置:任何一個(gè)ClassLoader的實(shí)例都應(yīng)該設(shè)置一個(gè)恰當(dāng)?shù)腃lassLoader實(shí)例為父類(lèi)加載器,并且在真正defineClass前,都應(yīng)該先將這個(gè)任務(wù)委托給其父類(lèi)加載器 。何為恰當(dāng)?shù)腃lassLoader實(shí)例?一般來(lái)說(shuō),就應(yīng)該是 this.getClass().getClassLoader()(也就是ClassName.class.getClassLoader(),這兩個(gè)值是同一個(gè)值)的返回值),或者是一個(gè)設(shè)計(jì)者認(rèn)為合理的值。這個(gè)值應(yīng)該保證“相同全限定名的類(lèi)(可以認(rèn)為是同一個(gè)類(lèi),僅僅是可以)不會(huì)出現(xiàn)在同一個(gè)類(lèi)的代碼中。” 舉例來(lái)說(shuō),在一個(gè)類(lèi)的一段代碼中(可以是一個(gè)方法,或者是一個(gè)static塊),如果有classLoaderA加載的 test.Test類(lèi),也有classLoaderB加載的test.Test,那么,把前者的引用指向后者的實(shí)例的時(shí)候,就會(huì)報(bào)LinkageError。

---------------------------------------------------------------------------------------------------------------------------------

以下是自己的測(cè)試:

Java代碼 復(fù)制代碼 收藏代碼
  1. public class Test24 {   
  2.     public static void main(String[] args){   
  3.         foo1();   
  4.     }   
  5.        
  6.     public static void foo1(){   
  7.         try{   
  8.             Test01 t1 = new Test01();   
  9. //          throw new RuntimeException();   
  10.         }catch(Exception e){   
  11.             System.out.println("111111111");   
  12.             //e.printStackTrace();   
  13.                
  14.         }finally{   
  15.             System.out.println("222222222");   
  16.         }   
  17.         System.out.println("333333333");   
  18.         int i=0;   
  19.         i++;   
  20.         System.out.println(i);   
  21.     }   
  22. }  
 
上述測(cè)試類(lèi)中正常編譯后將Test01.class刪除,然后再運(yùn)行Test24類(lèi),這是會(huì)報(bào):
222222222
Exception in thread "main" java.lang.NoClassDefFoundError: org/coffeesweet/test01/Test01
at org.coffeesweet.test01.Test24.foo1(Test24.java:21)
at org.coffeesweet.test01.Test24.main(Test24.java:16)
Caused by: java.lang.ClassNotFoundException: org.coffeesweet.test01.Test01
at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
... 2 more
可見(jiàn)NoClassDefFoundError用Exception是不能捕獲的,程序會(huì)終止。
需要catch(Throwable e)才能捕獲ERROR,修改以后可以繼續(xù)執(zhí)行完程序。
以下文章是來(lái)至網(wǎng)上的有關(guān)JAVA的異常的相關(guān)知識(shí),類(lèi)似ERROR的內(nèi)容大多是類(lèi)加載,鏈接,JVM內(nèi)部的錯(cuò)誤,
表現(xiàn)出最常見(jiàn)的是JAR包沖突的問(wèn)題,比如:編譯的時(shí)候引用的A類(lèi),執(zhí)行的時(shí)候?qū)類(lèi)換了一個(gè)版本,內(nèi)容變了,
但還叫A.class,這是就會(huì)報(bào)錯(cuò)誤了。這些是應(yīng)該讓程序終止,并找出問(wèn)題解決的,不能當(dāng)做普通的業(yè)務(wù)異常來(lái)處理。
他們不同于網(wǎng)絡(luò)超時(shí)等異常,這些是業(yè)務(wù)異常,不是由于JAVA本身的問(wèn)題導(dǎo)致的。

所以雖然可以捕獲這些錯(cuò)誤,用 catch(Throwable e) 的方式,但還是不建議這么做,業(yè)務(wù)代碼還是 catch (Exception e) ,

JAVA 系統(tǒng)級(jí)別的 ERROR ,系統(tǒng)解決完畢就行了。

參考:http://lvp./blog/356650
http://topic.csdn.net/t/20020524/17/749799.html
-----------------------------------------------------------------------------------------------
出自《JAVA程序設(shè)計(jì)》一書(shū)

8.3  Java 的異常處理

異常的處理主要包括捕獲異常、程序流程的跳轉(zhuǎn)和異常處理語(yǔ)句塊的定義等。當(dāng)一個(gè)異常被拋出時(shí),應(yīng)該有專(zhuān)門(mén)的語(yǔ)句來(lái)捕獲這個(gè)被拋出的異常對(duì)象,這個(gè)過(guò)程被稱(chēng)為捕獲異常。當(dāng)一個(gè)異常類(lèi)的對(duì)象被捕獲后,用戶程序就會(huì)發(fā)生流程的跳轉(zhuǎn),系統(tǒng)中止當(dāng)前的流程而跳轉(zhuǎn)至專(zhuān)門(mén)的異常處理語(yǔ)句塊,或直接跳出當(dāng)前程序和 Java 虛擬機(jī),退回到操作系統(tǒng)。

8.3.1   異常類(lèi)說(shuō)明

Java 中所有的異常都由類(lèi)來(lái)表示。所有的異常都是從一個(gè)名為 Throwable 的類(lèi)派生出來(lái)的。因此,當(dāng)程序中發(fā)生一個(gè)異常時(shí),就會(huì)生成一個(gè)異常類(lèi)的某種類(lèi)型的對(duì)象。 Throwable 類(lèi)有兩個(gè)直接子類(lèi): Exception Error 。

Error 類(lèi)型的異常相關(guān)的錯(cuò)誤發(fā)生在 Java 虛擬機(jī)中,而不是在程序中。錯(cuò)誤類(lèi)( Error )定義了被認(rèn)為是不能恢復(fù)的嚴(yán)重錯(cuò)誤條件。在大多數(shù)情況下,當(dāng)遇到這樣的錯(cuò)誤時(shí),建議讓該程序中斷。這樣的異常超出了程序可控制的范圍。

由程序運(yùn)行所導(dǎo)致的錯(cuò)誤由 Exception 類(lèi)來(lái)表示,該異常類(lèi)定義了程序中可能遇到的輕微的錯(cuò)誤條件。可以編寫(xiě)代碼來(lái)處理這樣的異常并繼續(xù)執(zhí)行程序,而不是讓程序中斷。它代表輕微的可以恢復(fù)的故障。接收到異常信號(hào)后,調(diào)用方法捕獲拋出的異常,在可能的情況下再恢復(fù)回來(lái),這樣程序員可以通過(guò)處理程序來(lái)處理異常。

Java 中的異常類(lèi)具有層次組織,其中 Throwable 類(lèi)是 Error 類(lèi)(錯(cuò)誤類(lèi))和 Exception 類(lèi)(異常類(lèi))的父類(lèi), Throwable 類(lèi)是 Object 類(lèi)的直接子類(lèi)。

異常類(lèi)( java.lang.Exception )繼承于 java.lang.Object 類(lèi)中的 java.lang.Throwable 類(lèi)。異??煞譃閳?zhí)行異常( Runtime Exception )和檢查異常( Checked Exception )兩種,如圖 8-1 所示。為了深入了解執(zhí)行異常和檢查異常內(nèi)容,這里給出它們的詳細(xì)介紹列舉。

8-1  異常類(lèi)的繼承結(jié)構(gòu)

1.執(zhí)行異常

執(zhí)行異常即運(yùn)行時(shí)異常,繼承于 Runtime Exception Java 編譯器允許程序不對(duì)它們做出處理。下面列出了主要的運(yùn)行時(shí)異常。

·     ArithmeticException 一個(gè)非法算術(shù)運(yùn)算產(chǎn)生的異常。

·     ArrayStoreException 存入數(shù)組的內(nèi)容數(shù)據(jù)類(lèi)型不一致所產(chǎn)生的異常。

·     ArrayIndexOutOfBoundsException 數(shù)組索引超出范圍所產(chǎn)生的異常。

·     ClassCastException 類(lèi)對(duì)象強(qiáng)迫轉(zhuǎn)換造成不當(dāng)類(lèi)對(duì)象所產(chǎn)生的異常。

·     IllegalArgumentException 程序調(diào)用時(shí),返回錯(cuò)誤自變量的數(shù)據(jù)類(lèi)型。

·     IllegalThreadStateException 線程在不合理狀態(tài)下運(yùn)行所產(chǎn)生的異常。

·     NumberFormatException 字符串轉(zhuǎn)換為數(shù)值所產(chǎn)生的異常。

·     IllegalMonitorStateException 線程等候或通知對(duì)象時(shí)所產(chǎn)生的異常。

·     IndexOutOfBoundsException 索引超出范圍所產(chǎn)生的異常。

·     NegativeException 數(shù)組建立負(fù)值索引所產(chǎn)生的異常。

·     NullPointerException 對(duì)象引用參考值為 null所產(chǎn)生的異常。

·     SecurityException 違反安全所產(chǎn)生的異常。

2.檢查異常

除了執(zhí)行異常外,其余的子類(lèi)是屬于檢查異常類(lèi)也稱(chēng)為非運(yùn)行時(shí)異常,它們都在 java.lang 類(lèi)庫(kù)內(nèi)定義。 Java 編譯器要求程序必須捕獲或者聲明拋棄這種異常。下面列出了主要的檢查異常。

·     ClassNotFoundException 找不到類(lèi)或接口所產(chǎn)生的異常。

·     CloneNotSupportedException 使用對(duì)象的 clone( )方法但無(wú)法執(zhí)行 Cloneable所產(chǎn)生的異常。

·     IllegalAccessException 類(lèi)定義不明確所產(chǎn)生的異常。

·     InstantiationException 使用 newInstance( )方法試圖建立一個(gè)類(lèi) instance時(shí)所產(chǎn)生的異常。

·     InterruptedException 目前線程等待執(zhí)行,另一線程中斷目前線程所產(chǎn)生的異常。

8.3.2   錯(cuò)誤分類(lèi)

Error 類(lèi)與異常一樣,它們都是繼承自 java.lang.Throwable 類(lèi)。 Error 類(lèi)對(duì)象由 Java 虛擬機(jī)生成并拋出。 Error 類(lèi)包括 LinkageError (結(jié)合錯(cuò)誤)與 VitualmanchineError (虛擬機(jī)錯(cuò)誤)兩種子類(lèi)。

1 LinkageError

LinkageError 類(lèi)的子類(lèi)表示一個(gè)類(lèi)信賴于另一個(gè)類(lèi),但是,在前一個(gè)類(lèi)編譯之后,后一個(gè)類(lèi)的改變會(huì)與它不兼容。

LinkageError 類(lèi)包括 ClassFormatError ClassCircularityError 、 ExceptionInitializerError 、 NoClassDeFormatError 、 VeritfyError UnsatisfidLinkError IncompatibleClassChangeError 等子類(lèi)。其中 NoIncompatibleClassChangeError 類(lèi)又包含 AbstractMethodError NoSuchField   Error 、 NoSuchMethodError 、 IllegalAccessError InstantiationError 子類(lèi)。這些類(lèi)所代表的意義如下所述。

·     ClassFormatError 類(lèi)格式所產(chǎn)生的錯(cuò)誤。

·     ClassCircularityError 無(wú)限循環(huán)所產(chǎn)生的錯(cuò)誤。

·     ExceptionInitializerError 初始化所產(chǎn)生的錯(cuò)誤。

·     NoClassDeFormatError 沒(méi)有類(lèi)定義所產(chǎn)生的錯(cuò)誤。

·     VeritfyError 類(lèi)文件某些數(shù)據(jù)不一致或安全問(wèn)題所產(chǎn)生的錯(cuò)誤。

·     UnsatisfidLinkError Java虛擬機(jī)無(wú)法找到合適的原始語(yǔ)言( Native-Language)定義的方法所產(chǎn)生的錯(cuò)誤。

·     IncompatibleClassChangeError 不兼容類(lèi)所產(chǎn)生的錯(cuò)誤。

·     AbtractMethodError 調(diào)用抽象方法所產(chǎn)生的錯(cuò)誤。

·     NoSuchFieldError 存取或改變數(shù)據(jù)域所產(chǎn)生的錯(cuò)誤。

·     NoSuchMethodError 調(diào)用類(lèi)方法所產(chǎn)生的錯(cuò)誤。

·     IllegalAccessError 不合法存取或改變數(shù)據(jù)域調(diào)用方法所產(chǎn)生的錯(cuò)誤。

·     InstantiationError 使用抽象類(lèi)或接口所產(chǎn)生的錯(cuò)誤。

2 VitualmachineError

當(dāng) Java 虛擬機(jī)崩潰了或用盡了它繼續(xù)操作所需的資源時(shí),拋出該錯(cuò)誤。

VitualmachineError 包含 InternalError OutOfMemoryError 、 StackOverflow Error UnknownError 。這些類(lèi)所代表的意義如下所述。

·     InternalError 虛擬機(jī)內(nèi)部所產(chǎn)生的錯(cuò)誤。

·     OutOfMemoryError 虛擬機(jī)內(nèi)存不足所產(chǎn)生的錯(cuò)誤。

·     StackOverflowError 堆棧無(wú)法容納所產(chǎn)生的錯(cuò)誤。

·     UnknownError 虛擬機(jī)不知名異常所產(chǎn)生的錯(cuò)誤。

8.3.3   異常處理機(jī)制

Java 提供了一種獨(dú)特的異常處理機(jī)制,通常通過(guò)異常來(lái)處理程序設(shè)計(jì)中可能出現(xiàn)的錯(cuò)誤

Java 程序的執(zhí)行過(guò)程中,如果出現(xiàn)了異常事件,就會(huì)生成一個(gè)異常對(duì)象;生成的異常對(duì)象將傳遞給 Java 運(yùn)行系統(tǒng),這一異常的產(chǎn)生和提交過(guò)程稱(chēng)為拋棄( Throw )異常。當(dāng) Java 運(yùn)行系統(tǒng)得到一個(gè)異常對(duì)象時(shí),它將會(huì)尋找處理這一異常的代碼,找到能夠處理這種類(lèi)型異常的方法后,運(yùn)行系統(tǒng)把當(dāng)前異常對(duì)象交給這個(gè)方法進(jìn)行處理,這一過(guò)程稱(chēng)為捕獲( Catch )異常。如果 Java 運(yùn)行系統(tǒng)找不到可以捕獲異常的方法,則運(yùn)行系統(tǒng)將終止,相應(yīng)的 Java 程序也將退出。

Java 異常處理是通過(guò) 5 個(gè)關(guān)鍵字來(lái)管理的。它們是 try 、 catch 、 throw throws finally, 將在下面的小節(jié)中詳細(xì)介紹。這里先大致給出它們的工作原理。

程序中需要被監(jiān)測(cè)的程序語(yǔ)句序列應(yīng)包含在一個(gè) try 代碼塊中。如果 try 代碼塊中有異常發(fā)生,那么就要拋出該異常??梢杂?/SPAN> catch 代碼塊來(lái)捕獲這個(gè)異常,并且在 catch 代碼塊中加以適當(dāng)?shù)奶幚?。系統(tǒng)產(chǎn)生的異常會(huì)由 Java 運(yùn)行系統(tǒng)自動(dòng)拋出。如果需要手動(dòng)拋出異常,則使用關(guān)鍵字 throw 。在某些情況下,從一個(gè)方法拋出的異常必須用一個(gè) throw 語(yǔ)句指定為異常。最后,從 try 代碼塊退出時(shí),必須執(zhí)行的代碼要放在一個(gè) finallly 代碼塊中。

異常機(jī)制提供了程序退出的安全通道。當(dāng)出現(xiàn)錯(cuò)誤后,程序執(zhí)行的流程發(fā)生改變,程序的控制權(quán)轉(zhuǎn)移到異常處理器。傳統(tǒng)的處理異常的辦法是:方法返回一個(gè)特殊的結(jié)果來(lái)表示出現(xiàn)異常,調(diào)用該方法的程序負(fù)責(zé)檢查并分析函數(shù)返回的結(jié)果并進(jìn)行相應(yīng)的處理。但是,這樣做有如下弊端:

·     函數(shù)返回 - 1代表出現(xiàn)異常,但是如果函數(shù)確實(shí)要返回 - 1這個(gè)正確的值時(shí),就會(huì)出現(xiàn)混淆。

·     可讀性降低,將程序代碼與處理異常的代碼交叉在一起。

·     由調(diào)用函數(shù)的程序來(lái)分析錯(cuò)誤,這就要求客戶程序員對(duì)庫(kù)函數(shù)有很深的了解。

J ava 的異常可以分為運(yùn)行時(shí)異常和非運(yùn)行時(shí)異常兩類(lèi)。繼承于 RuntimeException 的類(lèi)都屬于運(yùn)行時(shí)異常,例如算術(shù)異常、數(shù)組下標(biāo)越界異常等。由于這些異常產(chǎn)生的位置是未知的, Java 編譯器允許程序員在程序中不對(duì)它們做出處理。除了運(yùn)行時(shí)異常之外的其他由 Exception 繼承來(lái)的異常都是非運(yùn)行時(shí)異常, Java 編譯器要求在程序中必須處理這種異常 。

8.3.4   異常處理語(yǔ)句

異常處理的目的并不是為了避免發(fā)生異常,而是在異常發(fā)生時(shí)避免程序的異常終止,設(shè)法將損失降低到最小。

Java 的異常處理是通過(guò) 5 個(gè)關(guān)鍵詞來(lái)實(shí)現(xiàn)的: try catch 、 throw 、 throws finally 。一般情況下是用 try 來(lái)執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會(huì)拋出( throw )一個(gè)異常,這時(shí)候可以通過(guò)它的類(lèi)型來(lái)捕捉( catch )它,最后( finally )由默認(rèn)處理器來(lái)處理。

1 try/catch語(yǔ)句塊

Java 程序里,異常對(duì)象是依靠 try/catch 語(yǔ)句來(lái)捕獲和處理的。 try/catch 異常處理語(yǔ)句分為 try 語(yǔ)句塊和 catch 語(yǔ)句塊,其格式如下。

try{

    …… //try語(yǔ)句塊,可能產(chǎn)生異常的多個(gè)語(yǔ)句

}catch{

    …… //catch語(yǔ)句塊,對(duì)異常進(jìn)行處理

}

一般將可能產(chǎn)生異常情況語(yǔ)句放在 try 語(yǔ)句塊中,這個(gè) try 語(yǔ)句塊用來(lái)啟動(dòng) Java 的異常處理機(jī)制。凡是可能拋出異常的語(yǔ)句,包括 throw 語(yǔ)句和可能拋出異常的方法的調(diào)用語(yǔ)句,都應(yīng)該包含在這個(gè) try 語(yǔ)句塊中。然后在 catch 語(yǔ)句塊對(duì)異常進(jìn)行處理。 Java 語(yǔ)言還規(guī)定,每個(gè) catch 語(yǔ)句塊都應(yīng)該與一個(gè) try 語(yǔ)句塊相對(duì)應(yīng)。

【例 8-1 捕獲除數(shù)為零的異常,并顯示相應(yīng)信息。

class ArithmeticExceptionDemo{

    public static void main(String args[]) {

        int zero,aInt;

        try {// 監(jiān)視可能產(chǎn)生異常的代碼塊

            zero=0;

            aInt=68/zero;

            System.out.println("本字符串將不顯示。 ");

        }catch (ArithmeticException e) {       //捕獲 divide-by-zero錯(cuò)誤

            System.out.println("產(chǎn)生用零除錯(cuò)誤。 ");

        }

        System.out.println("在捕獲語(yǔ)句后執(zhí)行的一個(gè)語(yǔ)句。 ");

    }

}

該程序的執(zhí)行結(jié)果如圖 8-2 所示。

8-2  捕獲 divide-by-zero錯(cuò)誤的執(zhí)行結(jié)果

Try 語(yǔ)句塊中調(diào)用了可能拋出 ArithmeticException 的對(duì)象, catch 語(yǔ)句塊則專(zhuān)門(mén)用來(lái)捕獲這類(lèi)異常。可見(jiàn), catch 語(yǔ)句塊應(yīng)緊跟在 try 語(yǔ)句塊的后面。當(dāng) try 語(yǔ)句塊中的某條語(yǔ)句在執(zhí)行時(shí)產(chǎn)生了一個(gè)異常,此時(shí)被啟動(dòng)的異常處理機(jī)制會(huì)自動(dòng)捕獲到它,然后流程自動(dòng)跳過(guò)異常引發(fā)點(diǎn)后面的所有尚未執(zhí)行語(yǔ)句,而轉(zhuǎn)至 try 語(yǔ)句塊后面的 catch 語(yǔ)句塊,執(zhí)行 catch 語(yǔ)句塊中的語(yǔ)句。從執(zhí)行的結(jié)果還可以看出,異常被捕獲并執(zhí)行完 catch 語(yǔ)句塊中的語(yǔ)句后,繼續(xù)執(zhí)行 catch 語(yǔ)句塊之后的語(yǔ)句。如果沒(méi)有異常發(fā)生,則跳過(guò) catch 語(yǔ)句塊。

2 finally語(yǔ)句塊

finally 語(yǔ)句塊用來(lái)控制從 try-catch 語(yǔ)句轉(zhuǎn)移到另一部分之前的一些必要的善后工作,這些工作包括關(guān)閉文件或釋放其他有關(guān)系統(tǒng)資源等。 finally 語(yǔ)句塊中的語(yǔ)句是一種強(qiáng)制的、無(wú)條件執(zhí)行的語(yǔ)句,即無(wú)論在程序中是否出現(xiàn)異常,無(wú)論出現(xiàn)哪一種異常,也不管 try 代碼塊中是否包含有 break 、 continue return 或者 throw 語(yǔ)句,都必須執(zhí)行 finally 語(yǔ)句塊中所包含的語(yǔ)句。

finally 語(yǔ)句塊緊接著 try-catch 結(jié)構(gòu)中的最后一個(gè) catch 語(yǔ)句塊,其形式如下:

try{

        ……

}catch(Exception1 e1){

        ……

}catch(Exception2 e2){

        ……

} finally{

        ……

}

在出現(xiàn)和未出現(xiàn)異常的情況下都要執(zhí)行的代碼可以放到 finally 語(yǔ)句塊中。加入了 finally 語(yǔ)句塊后有以下 3 種執(zhí)行情況。

·     沒(méi)有拋出異常情況: 執(zhí)行 try語(yǔ)句塊后,再執(zhí)行 finally語(yǔ)句塊。

·     代碼拋出在 catch 語(yǔ)句塊中捕獲的一個(gè)異常情況: 這時(shí), Java執(zhí)行 try語(yǔ)句塊中直到這個(gè)異常情況被拋出為止的所有代碼,跳過(guò) try語(yǔ)句塊中剩余的代碼;然后執(zhí)行匹配的 catch語(yǔ)句塊中的代碼和 finally語(yǔ)句塊中的代碼。

·     代碼拋出了一個(gè)在 catch 語(yǔ)句塊中沒(méi)有捕獲到的異常情況: 這時(shí), Java執(zhí)行 try語(yǔ)句塊中直到這個(gè)異常情況被拋出為止的所有代碼,跳過(guò) try語(yǔ)句塊中剩余的代碼;然后執(zhí)行 finally語(yǔ)句塊中的代碼,并把這個(gè)異常情況拋回到這個(gè)方法的調(diào)用者。

【例 8-2 帶有 finally 語(yǔ)句塊的程序示例。

class Finally_Demo{

    public static void main(String args[]) {

        try{

            int x=0;

            int y=20;

            int z=y/x;

            System.out.println("y/x 的值是 :"+z);

        }catch(ArithmeticException e){

            System.out.println(" 捕獲到算術(shù)異常 "+e);

        }finally{

            System.out.println(" 執(zhí)行到 finally 塊內(nèi) ! ");

            try{

                String name=null;

                if(name.equals(" 王老三 ")){

                       // 字符串比較 , 判斷 name 是否為 " 王老三 "

                    System.out.println(" 的名字叫王老三。 ");

                 }

            }catch(Exception e){

                System.out.println(" 又捕獲到另一個(gè)異常 "+e);

            }finally{

                System.out.println(" 執(zhí)行到內(nèi)層的 finally 塊內(nèi) ! ");

            }

        }

    }

}

該程序的執(zhí)行結(jié)果如圖 8-3 所示。

8-3  帶有 finally語(yǔ)句塊的程序的執(zhí)行結(jié)果

Java 語(yǔ)言中, try-catch-finally 語(yǔ)句允許嵌套。本例就是將內(nèi)層的一個(gè) try 嵌套在外層的 finally 語(yǔ)句塊內(nèi)。在程序執(zhí)行到外層的 try 語(yǔ)句塊時(shí),由于分母為零而產(chǎn)生了算術(shù)異常,所以程序轉(zhuǎn)移到第一個(gè) catch 語(yǔ)句塊。該 catch 語(yǔ)句塊捕獲了這個(gè)算術(shù)異常,并進(jìn)行了處理,之后再轉(zhuǎn)向必須執(zhí)行的外層的 finally 語(yǔ)句塊。因?yàn)樵谠?/SPAN> finally 語(yǔ)句塊內(nèi)又產(chǎn)生了空指針異常(一個(gè) null 字符串和字符串"王老三"進(jìn)行比較),所以內(nèi)層 catch 語(yǔ)句塊又捕獲到 NullPointerException ,最后程序轉(zhuǎn)移到內(nèi)層的 finally 語(yǔ)句塊。

finally 語(yǔ)句塊還可以和 break 、 continue 以及 return 等流程控制語(yǔ)句一起使用。當(dāng) try 語(yǔ)句塊中出現(xiàn)了上述語(yǔ)句時(shí),程序必須先執(zhí)行 finally 語(yǔ)句塊,才能最終離開(kāi) try 語(yǔ)句塊。

【例 8-3 同時(shí)有 break 語(yǔ)句和 finally 語(yǔ)句塊的程序的執(zhí)行情況。

class FinallyWithBreakDemo{

    public static void main(String args[]) {

        for( ; ; )

        try{

             System.out.println("即將被 break中斷,要退出循環(huán)了 !");

            break;

        }finally{

            System.out.println("但是 finally塊總要被執(zhí)行到! ");

        }

    }

}

該程序的執(zhí)行結(jié)果如圖 8-4 所示。

8-4  同時(shí)有 finally語(yǔ)句塊和 break語(yǔ)句的程序的執(zhí)行結(jié)果

8.3.5   聲明異常

在某些情況下,如果一個(gè)方法產(chǎn)生自己不處理或無(wú)法處理的異常,它就必須在 throws 子句中聲明該異常。也就是說(shuō),在 Java 語(yǔ)言中如果在一個(gè)方法中生成了一個(gè)異常,但是這一方法并不確切地知道該如何對(duì)這一異常事件進(jìn)行處理,這時(shí),這個(gè)方法就應(yīng)該聲明拋棄異常,使得異常對(duì)象可以從調(diào)用棧向后傳播,直到有適合的方法捕獲它為止。

throws 關(guān)鍵字是在方法聲明中用來(lái)列出從方法中發(fā)出的非起源于 Error RutimeException 中的任何異常。能夠主動(dòng)引發(fā)異常的方法必須用 throws 來(lái)聲明。通常使用 Java 預(yù)定義的異常類(lèi)就可以滿足程序開(kāi)發(fā)者的編程需要。

聲明拋棄異常是在一個(gè)方法中的 throws 子句中指明的。

下面是包含 throws 子句的方法的基本形式。

[修飾符 ]  返回類(lèi)型   方法名(參數(shù) 1,參數(shù) 2,……) throws異常列表

   {…… }

例如:

public int read ( ) throws IOException

   {…… }

throws 子句中同時(shí)可以指明多個(gè)異常,說(shuō)明該方法將不對(duì)這些異常進(jìn)行處理,而是聲明拋棄它們。例如:

public static void main (String args[ ]) throws IOException, IndexOutOf-
BoudsException

   {…… }

【例 8-4 聲明拋出異常的程序格式。

import java.io.*;

public class ExceptionExam5

{

public static void go() throws IOException

    {//方法代碼 }

public static void main(String [] args)

{//程序入口主方法代碼 }

}

因?yàn)榭紤]到 go() 方法可能產(chǎn)生一個(gè) IOException ,而此時(shí)無(wú)法處理異常,所以要從 go() 方法拋出這個(gè)異常,并且需要用 throws 子句指定異常。另外, Java I/O 系統(tǒng)包含在 java.io 包中,因此 IOException 也包含在其中,所以使用語(yǔ)句“ import java.io.*; ”導(dǎo)入 java.io 包,然后可以直接引用 IOException 。

8.3.6   拋出異常

Java 應(yīng)用程序在運(yùn)行時(shí)如果出現(xiàn)了一個(gè)可識(shí)別的錯(cuò)誤,就會(huì)產(chǎn)生一個(gè)與該錯(cuò)誤相對(duì)應(yīng)的異常類(lèi)的對(duì)象。這個(gè)對(duì)象包含了異常的類(lèi)型和錯(cuò)誤出現(xiàn)時(shí)程序所處的狀態(tài)信息,該異常對(duì)象首先被交給 Java 虛擬機(jī),由虛擬機(jī)來(lái)尋找具體的異常處理者。在 Java 中把產(chǎn)生異常對(duì)象并將其交給 Java 虛擬機(jī)的過(guò)程稱(chēng)為拋出異常。

異常類(lèi)不同,拋出異常的方法也不同,可以分為以下兩種。

·     系統(tǒng)自動(dòng)拋出的異常。

·     語(yǔ)句拋出的異常。

系統(tǒng)定義的所有運(yùn)行異常都可以由系統(tǒng)自動(dòng)拋出。例如,以非法的算術(shù)操作引發(fā)的算術(shù)異常,這時(shí)系統(tǒng)拋出已定義好的異常類(lèi) ArithmeticException 的對(duì)象。前面列出的例子中,基本都屬于系統(tǒng)自動(dòng)拋出的異常。

語(yǔ)句拋出的異常是借助 throw 語(yǔ)句定義何種情況產(chǎn)生這種異常。用戶程序自定義的異常不可能依靠系統(tǒng)自動(dòng)拋出,必須使用 throw 語(yǔ)句拋出這個(gè)異常類(lèi)的新對(duì)象。系統(tǒng)定義的運(yùn)行異常也可以由 throw 語(yǔ)句拋出。用 throw 語(yǔ)句拋出異常對(duì)象的一般步驟如下:

1 )指定或定義一個(gè)合適的異常情況類(lèi)。

2 )產(chǎn)生這個(gè)類(lèi)的一個(gè)對(duì)象。

3 )拋出它。

例如:

EOFException e = new EOFException( );

throw e;

使用 throw 語(yǔ)句拋出異常有兩種方式:直接拋出和間接拋出。

1.直接拋出異常

直接拋出方式是直接利用 throw 語(yǔ)句將異常拋出,格式為:

throw newExceptionObject;

利用 throw 語(yǔ)句拋出一個(gè)異常后,程序執(zhí)行流程將直接尋找一個(gè)捕獲( catch )語(yǔ)句,并進(jìn)行匹配執(zhí)行相應(yīng)的異常處理程序,其后的所有語(yǔ)句都將被忽略。

【例 8-5 設(shè)計(jì)自己的異常類(lèi),從鍵盤(pán)輸入一個(gè) double 類(lèi)型的數(shù),若不小于 0.0 ,則輸出它的平方根;若小于 0.0 ,則輸出提示信息“輸入錯(cuò)誤”。

import java.io.*;

class MyException extends Exception{

    void test(double x) throws MyException{

        if(x<0.0) throw new MyException();  //條件成立時(shí),執(zhí)行 throw語(yǔ)句

        else System.out.println(Math.sqrt(x));

    }   

    public static void main(String args[]) throws IOException{

        MyException n = new MyException();

        try{

            System.out.print("求輸入實(shí)數(shù)的平方根。請(qǐng)輸入一個(gè)實(shí)數(shù): ");

             BufferedReader br=

                new BufferedReader(new InputStreamReader(System.in) );

            String s=br.readLine();

            n.test(Double.parseDouble(s));

        }catch(MyException e){

            System.out.println("輸入錯(cuò)誤! ");

        }

    }

}

程序的兩次運(yùn)行結(jié)果如圖 8-5 所示。

8-5  MyException類(lèi)的兩次運(yùn)行結(jié)果

在這個(gè)程序中,定義的異常類(lèi)通過(guò) extends 子句繼承了 Exception 異常類(lèi)。在 test( ) 方法中,用 throw 語(yǔ)句指定了可能拋出的異常,該語(yǔ)句在參數(shù)小于 0 時(shí)被執(zhí)行,產(chǎn)生并拋出異常 。

值得注意的是:在一個(gè)方法定義中如果采用了 throw 語(yǔ)句直接拋出異常,則該方法在發(fā)生異常的情況下可能沒(méi)有返回值。本例就屬于這種情況。

從本例也可以看出:由于系統(tǒng)不能識(shí)別用戶自定義的異常,所以需要編程人員在程序中的合適位置創(chuàng)建自定義異常的對(duì)象,并利用 throw 語(yǔ)句將這個(gè)新異常對(duì)象拋出。

2.間接拋出異常

Java 程序中,可以在方法的定義中利用 throws 關(guān)鍵字聲明異常類(lèi)型而間接拋出異常。也就是說(shuō),當(dāng) Java 程序中方法本身對(duì)其中出現(xiàn)的異常并不關(guān)心或不方便處理時(shí),可以不在方法實(shí)現(xiàn)中直接捕獲有關(guān)異常并進(jìn)行處理,而是在方法定義的時(shí)候通過(guò) throws 關(guān)鍵字,將異常拋給上層調(diào)用處理。其形式如下。

public void myMethod1() throws IndexOutOfBoundsException {

    ……

}

public void myMethod2() throws myException1, myException2 {

    ……

}

在上層調(diào)用該方法時(shí),必須捕獲有關(guān)異常,否則編譯時(shí)將會(huì)出錯(cuò)。例如,調(diào)用方法 myMethod2() 時(shí),必須按如下方式進(jìn)行。

try{

    myMethod2

}catch (MyExceptionl e1){

    ……

}catch(MyException2 e2){

    ……

}

【例 8-6 帶有間接拋出異常的類(lèi)。

public class OutOfRangeException extends Exception{

        public OutOfRangeException(){};

        public OutOfRangeException(Sting s){

            super(s);

        }

} // 定義一個(gè)異常類(lèi)

import OutOfRangeException;         //裝載異常類(lèi)

import java.io.*;

public class CreatingExceptions{

     private static BufferedReader in = new BufferedReader

         (new InputStreamReader(System.in));

    public static void main (String[] args) throws OutOfRangeException{

         final int MIN = 25, MAX = 40;

         int value;

         OutOfRangeException problem =

             new OutOfRangeException ("Input value is out of range.");

            //創(chuàng)建一個(gè)異常對(duì)象并可能拋出它

         System.out.print ("Enter an integer value between " + MIN +

                               " and " + MAX + ", inclusive: ");

         try{

             value = Integer.parseInt (in.readLine());

         }catch (Exception exception) {

              System.out.println ("Error reading int data, MIN_VALUE value

                                     returned.");

             value = Integer.MIN_VALUE;

          }

               //確定該異常是否拋出

         if (value < MIN || value > MAX)

             throw problem;

         System.out.println ("End of main method.");

             //may never reach this place

    }

}

這個(gè)例子有兩個(gè)特征,一是它利用了自定義的異常類(lèi) OutOfRangeException ,一旦程序執(zhí)行違背了所定義的邏輯就拋出這個(gè)異常;二是在拋出異常的方法中,利用 throws 關(guān)鍵字聲明了 OutOfRangeException 異常類(lèi)的間接拋出,這樣若是在其他地方使用到這個(gè)類(lèi)的對(duì)象,也可以捕獲這個(gè)異常。

使用 throws 子句拋出異常時(shí)應(yīng)注意如下兩個(gè)問(wèn)題。

·     一般這種拋出異常的語(yǔ)句應(yīng)該被定義為在滿足一定條件時(shí)執(zhí)行,例如把 throws子句放在 if語(yǔ)句的條件分支中,只有當(dāng)條件得到滿足,即用戶定義的邏輯錯(cuò)誤發(fā)生時(shí)才拋出。例如,例 8-6中的條件( value < MIN || value > MAX)滿足時(shí),拋出異常。

·     對(duì)于含有 throws子句的方法,應(yīng)該在方法頭定義中增加如下部分。

throws異常類(lèi)名列表

這樣做主要是為了通知所有欲調(diào)用此方法的方法:由于該方法包含 throws了句,所以要準(zhǔn)備接受和處理它在運(yùn)行過(guò)程中可能會(huì)拋出的異常。如果方法中的 throws了句不止一個(gè),方法頭的異常類(lèi)名表中的列出的異常也不止一個(gè),應(yīng)該包含所有可能產(chǎn)生的異常。例如,在上面的 myMethod2( ) 方法中包含的異常有: myException1 myException2 。

注意: 執(zhí)行 throws子語(yǔ)句將中斷程序的執(zhí)行,也就是說(shuō) throws的下一條語(yǔ)句將暫停執(zhí)行。

8.3.7   自定義異常類(lèi)

在實(shí)際的編程中并不一定非要使用 Java 已經(jīng)定義的異常,經(jīng)常需要?jiǎng)?chuàng)建自己的異常,以便指出編寫(xiě)的代碼可能生成的一個(gè)特殊錯(cuò)誤。創(chuàng)建自己的異常類(lèi),必須從一個(gè)現(xiàn)有的異常類(lèi)型(最終繼承自 Throwable 類(lèi))繼承。繼承一個(gè)異常同繼承一個(gè)普通的類(lèi)的方法是一樣的 。

Java 提供的一些異常有時(shí)候不能滿足編程的需求,例如規(guī)定用戶輸入數(shù)據(jù)的范圍在 20 30 之間,但是 Java 并沒(méi)有這個(gè)方面的異常,這時(shí)就可以應(yīng)用自定義的異常來(lái)規(guī)范化客戶的數(shù)據(jù)輸入。

Java 中進(jìn)行自定義異常時(shí),自定義異常類(lèi)必須是 Throwable 類(lèi)的直接或間接子類(lèi)。下面的例子是關(guān)于自定義異常的。它通過(guò)繼承 Exception 類(lèi)而繼承 Throwable 類(lèi),即間接繼承 Throwable 類(lèi)。

【例 8-7 自定義異常類(lèi)程序示例。

class OutBoundsException extends Exception

{

    OutBoundsException (String mes)

    {

        // 調(diào)用超類(lèi)的構(gòu)造函數(shù)

        super(mes);

    }

}

class check

{

    String ChecktheNum(int n) throws OutBoundsException

    {

        Integer N=new Integer(n);

         if(n>30||n<20)

    throw  new OutBoundsException("the number is out of bound!!");

        else

        return "the number"+N.toString()+"is in the bound!!";

    }

}

class Test

{

    public static void main(String []args)

    {

        try

        {

             check c=new check();

            System.out.println(" 以下是合法的數(shù)據(jù)的報(bào)告! ");

            System.out.println(c.ChecktheNum(25));

            System.out.println(" 以下是非法的數(shù)據(jù)的報(bào)告! ");

            System.out.println(c.ChecktheNum(5));

        }

        catch(OutBoundsException e)

        {

            System.out.println(e.toString());

        }

    }

}

運(yùn)行結(jié)果如圖 8-6 所示。

8-6  運(yùn)行結(jié)果

注意: 一個(gè)方法所聲明拋棄的異常是作為這個(gè)方法與外界交互的一部分而存在的。 所以,方法的調(diào)用者必須了解這些異常,并確定如何正確地處理它們。

<!-- 廣告位 --> <script></script><script></script><script></script><script></script><script></script>
---------------------------------------------------------------------------------------------------


<script></script>

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多