有關(guān)JAVA異常和錯誤(ERROR)的處理最近遇到有關(guān)ERROR的處理問題,下面這篇文章 轉(zhuǎn)至:http://www.cnblogs.com/deepnighttwo/archive/2006/12/11/1964305.html LinkageError是一個比較棘手的異常,準(zhǔn)確的說它是一個Error而不是Exception。java api對它沒有直接的解釋,而是介紹了它的子類: 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. 似乎是說不兼容性,既編譯時(shí),A類用到B類,且這時(shí)候A和B是兼容的,但是到運(yùn)行時(shí),A類得到的B(既某個類加載器加載的B類)卻不是A在編譯的時(shí)候那個與之兼容的B,這個說起來比較復(fù)雜,其實(shí)就是個二進(jìn)制兼容性問題,和很多程序不能在98上跑是一個道理,程序就是A,而98就是B。
事實(shí)上,真正出現(xiàn)二進(jìn)制兼容性問題的時(shí)候,確實(shí)是報(bào)NoSuchMethodError或者NoSuchFieldError或者NoClassDefFoundError。Java api對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的例子,或者說incompatibly changed)問題發(fā)生的時(shí)候,java會報(bào)NoSuchMethodError,NoSuchFieldError或者NoClassDefFoundError ,這三個類都是LinkageError的子類,所以,就好像java api對LinkageError中的解釋一樣“Subclasses of LinkageError indicate that……”這個解釋并沒有說LinkageError本身應(yīng)該是在什么情況下被拋出。倒不是java api顧左右而言他,而是拋出LinkageError的情況實(shí)在是很難敘述,《深入java虛擬機(jī)》第二版用近乎一章(比較大的一章,和其它章相比)來解釋這個問題。歸根結(jié)底,原因是ClassLoader沒有完全按照設(shè)計(jì)的那樣設(shè)置:任何一個ClassLoader的實(shí)例都應(yīng)該設(shè)置一個恰當(dāng)?shù)腃lassLoader實(shí)例為父類加載器,并且在真正defineClass前,都應(yīng)該先將這個任務(wù)委托給其父類加載器 。何為恰當(dāng)?shù)腃lassLoader實(shí)例?一般來說,就應(yīng)該是 this.getClass().getClassLoader()(也就是ClassName.class.getClassLoader(),這兩個值是同一個值)的返回值),或者是一個設(shè)計(jì)者認(rèn)為合理的值。這個值應(yīng)該保證“相同全限定名的類(可以認(rèn)為是同一個類,僅僅是可以)不會出現(xiàn)在同一個類的代碼中。” 舉例來說,在一個類的一段代碼中(可以是一個方法,或者是一個static塊),如果有classLoaderA加載的 test.Test類,也有classLoaderB加載的test.Test,那么,把前者的引用指向后者的實(shí)例的時(shí)候,就會報(bào)LinkageError。 ---------------------------------------------------------------------------------------------------------------------------------
以下是自己的測試:
public class Test24 { public static void main(String[] args){ foo1(); } public static void foo1(){ try{ Test01 t1 = new Test01(); // throw new RuntimeException(); }catch(Exception e){ System.out.println("111111111"); //e.printStackTrace(); }finally{ System.out.println("222222222"); } System.out.println("333333333"); int i=0; i++; System.out.println(i); } } 上述測試類中正常編譯后將Test01.class刪除,然后再運(yùn)行Test24類,這是會報(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 可見NoClassDefFoundError用Exception是不能捕獲的,程序會終止。
需要catch(Throwable e)才能捕獲ERROR,修改以后可以繼續(xù)執(zhí)行完程序。
以下文章是來至網(wǎng)上的有關(guān)JAVA的異常的相關(guān)知識,類似ERROR的內(nèi)容大多是類加載,鏈接,JVM內(nèi)部的錯誤,
表現(xiàn)出最常見的是JAR包沖突的問題,比如:編譯的時(shí)候引用的A類,執(zhí)行的時(shí)候?qū)類換了一個版本,內(nèi)容變了,
但還叫A.class,這是就會報(bào)錯誤了。這些是應(yīng)該讓程序終止,并找出問題解決的,不能當(dāng)做普通的業(yè)務(wù)異常來處理。
他們不同于網(wǎng)絡(luò)超時(shí)等異常,這些是業(yè)務(wù)異常,不是由于JAVA本身的問題導(dǎo)致的。
所以雖然可以捕獲這些錯誤,用 catch(Throwable e) 的方式,但還是不建議這么做,業(yè)務(wù)代碼還是 catch (Exception e) , JAVA 系統(tǒng)級別的 ERROR ,系統(tǒng)解決完畢就行了。
參考:http://lvp./blog/356650
http://topic.csdn.net/t/20020524/17/749799.html
-----------------------------------------------------------------------------------------------
出自《JAVA程序設(shè)計(jì)》一書
8.3 Java 的異常處理異常的處理主要包括捕獲異常、程序流程的跳轉(zhuǎn)和異常處理語句塊的定義等。當(dāng)一個異常被拋出時(shí),應(yīng)該有專門的語句來捕獲這個被拋出的異常對象,這個過程被稱為捕獲異常。當(dāng)一個異常類的對象被捕獲后,用戶程序就會發(fā)生流程的跳轉(zhuǎn),系統(tǒng)中止當(dāng)前的流程而跳轉(zhuǎn)至專門的異常處理語句塊,或直接跳出當(dāng)前程序和 Java 虛擬機(jī),退回到操作系統(tǒng)。 8.3.1 異常類說明Java 中所有的異常都由類來表示。所有的異常都是從一個名為 Throwable 的類派生出來的。因此,當(dāng)程序中發(fā)生一個異常時(shí),就會生成一個異常類的某種類型的對象。 Throwable 類有兩個直接子類: Exception 和 Error 。 與 Error 類型的異常相關(guān)的錯誤發(fā)生在 Java 虛擬機(jī)中,而不是在程序中。錯誤類( Error )定義了被認(rèn)為是不能恢復(fù)的嚴(yán)重錯誤條件。在大多數(shù)情況下,當(dāng)遇到這樣的錯誤時(shí),建議讓該程序中斷。這樣的異常超出了程序可控制的范圍。 由程序運(yùn)行所導(dǎo)致的錯誤由 Exception 類來表示,該異常類定義了程序中可能遇到的輕微的錯誤條件??梢跃帉懘a來處理這樣的異常并繼續(xù)執(zhí)行程序,而不是讓程序中斷。它代表輕微的可以恢復(fù)的故障。接收到異常信號后,調(diào)用方法捕獲拋出的異常,在可能的情況下再恢復(fù)回來,這樣程序員可以通過處理程序來處理異常。 Java 中的異常類具有層次組織,其中 Throwable 類是 Error 類(錯誤類)和 Exception 類(異常類)的父類, Throwable 類是 Object 類的直接子類。 異常類( java.lang.Exception )繼承于 java.lang.Object 類中的 java.lang.Throwable 類。異常可分為執(zhí)行異常( Runtime Exception )和檢查異常( Checked Exception )兩種,如圖 8-1 所示。為了深入了解執(zhí)行異常和檢查異常內(nèi)容,這里給出它們的詳細(xì)介紹列舉。 圖 8-1 異常類的繼承結(jié)構(gòu) 1.執(zhí)行異常執(zhí)行異常即運(yùn)行時(shí)異常,繼承于 Runtime Exception 。 Java 編譯器允許程序不對它們做出處理。下面列出了主要的運(yùn)行時(shí)異常。 · ArithmeticException : 一個非法算術(shù)運(yùn)算產(chǎn)生的異常。 · ArrayStoreException : 存入數(shù)組的內(nèi)容數(shù)據(jù)類型不一致所產(chǎn)生的異常。 · ArrayIndexOutOfBoundsException : 數(shù)組索引超出范圍所產(chǎn)生的異常。 · ClassCastException : 類對象強(qiáng)迫轉(zhuǎn)換造成不當(dāng)類對象所產(chǎn)生的異常。 · IllegalArgumentException : 程序調(diào)用時(shí),返回錯誤自變量的數(shù)據(jù)類型。 · IllegalThreadStateException : 線程在不合理狀態(tài)下運(yùn)行所產(chǎn)生的異常。 · NumberFormatException : 字符串轉(zhuǎn)換為數(shù)值所產(chǎn)生的異常。 · IllegalMonitorStateException : 線程等候或通知對象時(shí)所產(chǎn)生的異常。 · IndexOutOfBoundsException : 索引超出范圍所產(chǎn)生的異常。 · NegativeException : 數(shù)組建立負(fù)值索引所產(chǎn)生的異常。 · NullPointerException : 對象引用參考值為 null所產(chǎn)生的異常。 · SecurityException : 違反安全所產(chǎn)生的異常。 2.檢查異常除了執(zhí)行異常外,其余的子類是屬于檢查異常類也稱為非運(yùn)行時(shí)異常,它們都在 java.lang 類庫內(nèi)定義。 Java 編譯器要求程序必須捕獲或者聲明拋棄這種異常。下面列出了主要的檢查異常。 · ClassNotFoundException : 找不到類或接口所產(chǎn)生的異常。 · CloneNotSupportedException : 使用對象的 clone( )方法但無法執(zhí)行 Cloneable所產(chǎn)生的異常。 · IllegalAccessException : 類定義不明確所產(chǎn)生的異常。 · InstantiationException : 使用 newInstance( )方法試圖建立一個類 instance時(shí)所產(chǎn)生的異常。 · InterruptedException : 目前線程等待執(zhí)行,另一線程中斷目前線程所產(chǎn)生的異常。 8.3.2 錯誤分類Error 類與異常一樣,它們都是繼承自 java.lang.Throwable 類。 Error 類對象由 Java 虛擬機(jī)生成并拋出。 Error 類包括 LinkageError (結(jié)合錯誤)與 VitualmanchineError (虛擬機(jī)錯誤)兩種子類。 1. LinkageErrorLinkageError 類的子類表示一個類信賴于另一個類,但是,在前一個類編譯之后,后一個類的改變會與它不兼容。 LinkageError 類包括 ClassFormatError 、 ClassCircularityError 、 ExceptionInitializerError 、 NoClassDeFormatError 、 VeritfyError 、 UnsatisfidLinkError 和 IncompatibleClassChangeError 等子類。其中 NoIncompatibleClassChangeError 類又包含 AbstractMethodError 、 NoSuchField Error 、 NoSuchMethodError 、 IllegalAccessError 和 InstantiationError 子類。這些類所代表的意義如下所述。 · ClassFormatError : 類格式所產(chǎn)生的錯誤。 · ClassCircularityError : 無限循環(huán)所產(chǎn)生的錯誤。 · ExceptionInitializerError : 初始化所產(chǎn)生的錯誤。 · NoClassDeFormatError : 沒有類定義所產(chǎn)生的錯誤。 · VeritfyError : 類文件某些數(shù)據(jù)不一致或安全問題所產(chǎn)生的錯誤。 · UnsatisfidLinkError : Java虛擬機(jī)無法找到合適的原始語言( Native-Language)定義的方法所產(chǎn)生的錯誤。 · IncompatibleClassChangeError : 不兼容類所產(chǎn)生的錯誤。 · AbtractMethodError : 調(diào)用抽象方法所產(chǎn)生的錯誤。 · NoSuchFieldError : 存取或改變數(shù)據(jù)域所產(chǎn)生的錯誤。 · NoSuchMethodError : 調(diào)用類方法所產(chǎn)生的錯誤。 · IllegalAccessError : 不合法存取或改變數(shù)據(jù)域調(diào)用方法所產(chǎn)生的錯誤。 · InstantiationError : 使用抽象類或接口所產(chǎn)生的錯誤。 2. VitualmachineError當(dāng) Java 虛擬機(jī)崩潰了或用盡了它繼續(xù)操作所需的資源時(shí),拋出該錯誤。 VitualmachineError 包含 InternalError 、 OutOfMemoryError 、 StackOverflow Error 和 UnknownError 。這些類所代表的意義如下所述。 · InternalError : 虛擬機(jī)內(nèi)部所產(chǎn)生的錯誤。 · OutOfMemoryError : 虛擬機(jī)內(nèi)存不足所產(chǎn)生的錯誤。 · StackOverflowError : 堆棧無法容納所產(chǎn)生的錯誤。 · UnknownError : 虛擬機(jī)不知名異常所產(chǎn)生的錯誤。 8.3.3 異常處理機(jī)制Java 提供了一種獨(dú)特的異常處理機(jī)制,通常通過異常來處理程序設(shè)計(jì)中可能出現(xiàn)的錯誤 。 在 Java 程序的執(zhí)行過程中,如果出現(xiàn)了異常事件,就會生成一個異常對象;生成的異常對象將傳遞給 Java 運(yùn)行系統(tǒng),這一異常的產(chǎn)生和提交過程稱為拋棄( Throw )異常。當(dāng) Java 運(yùn)行系統(tǒng)得到一個異常對象時(shí),它將會尋找處理這一異常的代碼,找到能夠處理這種類型異常的方法后,運(yùn)行系統(tǒng)把當(dāng)前異常對象交給這個方法進(jìn)行處理,這一過程稱為捕獲( Catch )異常。如果 Java 運(yùn)行系統(tǒng)找不到可以捕獲異常的方法,則運(yùn)行系統(tǒng)將終止,相應(yīng)的 Java 程序也將退出。 Java 異常處理是通過 5 個關(guān)鍵字來管理的。它們是 try 、 catch 、 throw 、 throws 和 finally, 將在下面的小節(jié)中詳細(xì)介紹。這里先大致給出它們的工作原理。 程序中需要被監(jiān)測的程序語句序列應(yīng)包含在一個 try 代碼塊中。如果 try 代碼塊中有異常發(fā)生,那么就要拋出該異常??梢杂?/SPAN> catch 代碼塊來捕獲這個異常,并且在 catch 代碼塊中加以適當(dāng)?shù)奶幚?。系統(tǒng)產(chǎn)生的異常會由 Java 運(yùn)行系統(tǒng)自動拋出。如果需要手動拋出異常,則使用關(guān)鍵字 throw 。在某些情況下,從一個方法拋出的異常必須用一個 throw 語句指定為異常。最后,從 try 代碼塊退出時(shí),必須執(zhí)行的代碼要放在一個 finallly 代碼塊中。 異常機(jī)制提供了程序退出的安全通道。當(dāng)出現(xiàn)錯誤后,程序執(zhí)行的流程發(fā)生改變,程序的控制權(quán)轉(zhuǎn)移到異常處理器。傳統(tǒng)的處理異常的辦法是:方法返回一個特殊的結(jié)果來表示出現(xiàn)異常,調(diào)用該方法的程序負(fù)責(zé)檢查并分析函數(shù)返回的結(jié)果并進(jìn)行相應(yīng)的處理。但是,這樣做有如下弊端: · 函數(shù)返回 - 1代表出現(xiàn)異常,但是如果函數(shù)確實(shí)要返回 - 1這個正確的值時(shí),就會出現(xiàn)混淆。 · 可讀性降低,將程序代碼與處理異常的代碼交叉在一起。 · 由調(diào)用函數(shù)的程序來分析錯誤,這就要求客戶程序員對庫函數(shù)有很深的了解。 J ava 的異??梢苑譃檫\(yùn)行時(shí)異常和非運(yùn)行時(shí)異常兩類。繼承于 RuntimeException 的類都屬于運(yùn)行時(shí)異常,例如算術(shù)異常、數(shù)組下標(biāo)越界異常等。由于這些異常產(chǎn)生的位置是未知的, Java 編譯器允許程序員在程序中不對它們做出處理。除了運(yùn)行時(shí)異常之外的其他由 Exception 繼承來的異常都是非運(yùn)行時(shí)異常, Java 編譯器要求在程序中必須處理這種異常 。 8.3.4 異常處理語句異常處理的目的并不是為了避免發(fā)生異常,而是在異常發(fā)生時(shí)避免程序的異常終止,設(shè)法將損失降低到最小。 Java 的異常處理是通過 5 個關(guān)鍵詞來實(shí)現(xiàn)的: try 、 catch 、 throw 、 throws 和 finally 。一般情況下是用 try 來執(zhí)行一段程序,如果出現(xiàn)異常,系統(tǒng)會拋出( throw )一個異常,這時(shí)候可以通過它的類型來捕捉( catch )它,最后( finally )由默認(rèn)處理器來處理。 1. try/catch語句塊在 Java 程序里,異常對象是依靠 try/catch 語句來捕獲和處理的。 try/catch 異常處理語句分為 try 語句塊和 catch 語句塊,其格式如下。 try{ …… //try語句塊,可能產(chǎn)生異常的多個語句 }catch{ …… //catch語句塊,對異常進(jìn)行處理 } 一般將可能產(chǎn)生異常情況語句放在 try 語句塊中,這個 try 語句塊用來啟動 Java 的異常處理機(jī)制。凡是可能拋出異常的語句,包括 throw 語句和可能拋出異常的方法的調(diào)用語句,都應(yīng)該包含在這個 try 語句塊中。然后在 catch 語句塊對異常進(jìn)行處理。 Java 語言還規(guī)定,每個 catch 語句塊都應(yīng)該與一個 try 語句塊相對應(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錯誤 System.out.println("產(chǎn)生用零除錯誤。 "); } System.out.println("在捕獲語句后執(zhí)行的一個語句。 "); } } 該程序的執(zhí)行結(jié)果如圖 8-2 所示。 圖 8-2 捕獲 divide-by-zero錯誤的執(zhí)行結(jié)果 Try 語句塊中調(diào)用了可能拋出 ArithmeticException 的對象, catch 語句塊則專門用來捕獲這類異常??梢?, catch 語句塊應(yīng)緊跟在 try 語句塊的后面。當(dāng) try 語句塊中的某條語句在執(zhí)行時(shí)產(chǎn)生了一個異常,此時(shí)被啟動的異常處理機(jī)制會自動捕獲到它,然后流程自動跳過異常引發(fā)點(diǎn)后面的所有尚未執(zhí)行語句,而轉(zhuǎn)至 try 語句塊后面的 catch 語句塊,執(zhí)行 catch 語句塊中的語句。從執(zhí)行的結(jié)果還可以看出,異常被捕獲并執(zhí)行完 catch 語句塊中的語句后,繼續(xù)執(zhí)行 catch 語句塊之后的語句。如果沒有異常發(fā)生,則跳過 catch 語句塊。 2. finally語句塊finally 語句塊用來控制從 try-catch 語句轉(zhuǎn)移到另一部分之前的一些必要的善后工作,這些工作包括關(guān)閉文件或釋放其他有關(guān)系統(tǒng)資源等。 finally 語句塊中的語句是一種強(qiáng)制的、無條件執(zhí)行的語句,即無論在程序中是否出現(xiàn)異常,無論出現(xiàn)哪一種異常,也不管 try 代碼塊中是否包含有 break 、 continue 、 return 或者 throw 語句,都必須執(zhí)行 finally 語句塊中所包含的語句。 finally 語句塊緊接著 try-catch 結(jié)構(gòu)中的最后一個 catch 語句塊,其形式如下: try{ …… }catch(Exception1 e1){ …… }catch(Exception2 e2){ …… } finally{ …… } 在出現(xiàn)和未出現(xiàn)異常的情況下都要執(zhí)行的代碼可以放到 finally 語句塊中。加入了 finally 語句塊后有以下 3 種執(zhí)行情況。 · 沒有拋出異常情況: 執(zhí)行 try語句塊后,再執(zhí)行 finally語句塊。 · 代碼拋出在 catch 語句塊中捕獲的一個異常情況: 這時(shí), Java執(zhí)行 try語句塊中直到這個異常情況被拋出為止的所有代碼,跳過 try語句塊中剩余的代碼;然后執(zhí)行匹配的 catch語句塊中的代碼和 finally語句塊中的代碼。 · 代碼拋出了一個在 catch 語句塊中沒有捕獲到的異常情況: 這時(shí), Java執(zhí)行 try語句塊中直到這個異常情況被拋出為止的所有代碼,跳過 try語句塊中剩余的代碼;然后執(zhí)行 finally語句塊中的代碼,并把這個異常情況拋回到這個方法的調(diào)用者。 【例 8-2 】 帶有 finally 語句塊的程序示例。 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(" 又捕獲到另一個異常 : "+e); }finally{ System.out.println(" 執(zhí)行到內(nèi)層的 finally 塊內(nèi) ! "); } } } } 該程序的執(zhí)行結(jié)果如圖 8-3 所示。 圖 8-3 帶有 finally語句塊的程序的執(zhí)行結(jié)果 在 Java 語言中, try-catch-finally 語句允許嵌套。本例就是將內(nèi)層的一個 try 嵌套在外層的 finally 語句塊內(nèi)。在程序執(zhí)行到外層的 try 語句塊時(shí),由于分母為零而產(chǎn)生了算術(shù)異常,所以程序轉(zhuǎn)移到第一個 catch 語句塊。該 catch 語句塊捕獲了這個算術(shù)異常,并進(jìn)行了處理,之后再轉(zhuǎn)向必須執(zhí)行的外層的 finally 語句塊。因?yàn)樵谠?/SPAN> finally 語句塊內(nèi)又產(chǎn)生了空指針異常(一個 null 字符串和字符串"王老三"進(jìn)行比較),所以內(nèi)層 catch 語句塊又捕獲到 NullPointerException ,最后程序轉(zhuǎn)移到內(nèi)層的 finally 語句塊。 finally 語句塊還可以和 break 、 continue 以及 return 等流程控制語句一起使用。當(dāng) try 語句塊中出現(xiàn)了上述語句時(shí),程序必須先執(zhí)行 finally 語句塊,才能最終離開 try 語句塊。 【例 8-3 】 同時(shí)有 break 語句和 finally 語句塊的程序的執(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語句塊和 break語句的程序的執(zhí)行結(jié)果 8.3.5 聲明異常在某些情況下,如果一個方法產(chǎn)生自己不處理或無法處理的異常,它就必須在 throws 子句中聲明該異常。也就是說,在 Java 語言中如果在一個方法中生成了一個異常,但是這一方法并不確切地知道該如何對這一異常事件進(jìn)行處理,這時(shí),這個方法就應(yīng)該聲明拋棄異常,使得異常對象可以從調(diào)用棧向后傳播,直到有適合的方法捕獲它為止。 throws 關(guān)鍵字是在方法聲明中用來列出從方法中發(fā)出的非起源于 Error 或 RutimeException 中的任何異常。能夠主動引發(fā)異常的方法必須用 throws 來聲明。通常使用 Java 預(yù)定義的異常類就可以滿足程序開發(fā)者的編程需要。 聲明拋棄異常是在一個方法中的 throws 子句中指明的。 下面是包含 throws 子句的方法的基本形式。 [修飾符 ] 返回類型 方法名(參數(shù) 1,參數(shù) 2,……) throws異常列表 {…… } 例如: public int read ( ) throws IOException {…… } throws 子句中同時(shí)可以指明多個異常,說明該方法將不對這些異常進(jìn)行處理,而是聲明拋棄它們。例如: public static void main (String args[ ]) throws IOException, IndexOutOf- {…… } 【例 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)生一個 IOException ,而此時(shí)無法處理異常,所以要從 go() 方法拋出這個異常,并且需要用 throws 子句指定異常。另外, Java 的 I/O 系統(tǒng)包含在 java.io 包中,因此 IOException 也包含在其中,所以使用語句“ import java.io.*; ”導(dǎo)入 java.io 包,然后可以直接引用 IOException 。 8.3.6 拋出異常Java 應(yīng)用程序在運(yùn)行時(shí)如果出現(xiàn)了一個可識別的錯誤,就會產(chǎn)生一個與該錯誤相對應(yīng)的異常類的對象。這個對象包含了異常的類型和錯誤出現(xiàn)時(shí)程序所處的狀態(tài)信息,該異常對象首先被交給 Java 虛擬機(jī),由虛擬機(jī)來尋找具體的異常處理者。在 Java 中把產(chǎn)生異常對象并將其交給 Java 虛擬機(jī)的過程稱為拋出異常。 異常類不同,拋出異常的方法也不同,可以分為以下兩種。 · 系統(tǒng)自動拋出的異常。 · 語句拋出的異常。 系統(tǒng)定義的所有運(yùn)行異常都可以由系統(tǒng)自動拋出。例如,以非法的算術(shù)操作引發(fā)的算術(shù)異常,這時(shí)系統(tǒng)拋出已定義好的異常類 ArithmeticException 的對象。前面列出的例子中,基本都屬于系統(tǒng)自動拋出的異常。 語句拋出的異常是借助 throw 語句定義何種情況產(chǎn)生這種異常。用戶程序自定義的異常不可能依靠系統(tǒng)自動拋出,必須使用 throw 語句拋出這個異常類的新對象。系統(tǒng)定義的運(yùn)行異常也可以由 throw 語句拋出。用 throw 語句拋出異常對象的一般步驟如下: ( 1 )指定或定義一個合適的異常情況類。 ( 2 )產(chǎn)生這個類的一個對象。 ( 3 )拋出它。 例如: EOFException e = new EOFException( ); throw e; 使用 throw 語句拋出異常有兩種方式:直接拋出和間接拋出。 1.直接拋出異常直接拋出方式是直接利用 throw 語句將異常拋出,格式為: throw newExceptionObject; 利用 throw 語句拋出一個異常后,程序執(zhí)行流程將直接尋找一個捕獲( catch )語句,并進(jìn)行匹配執(zhí)行相應(yīng)的異常處理程序,其后的所有語句都將被忽略。 【例 8-5 】 設(shè)計(jì)自己的異常類,從鍵盤輸入一個 double 類型的數(shù),若不小于 0.0 ,則輸出它的平方根;若小于 0.0 ,則輸出提示信息“輸入錯誤”。 import java.io.*; class MyException extends Exception{ void test(double x) throws MyException{ if(x<0.0) throw new MyException(); //條件成立時(shí),執(zhí)行 throw語句 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ù)的平方根。請輸入一個實(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("輸入錯誤! "); } } } 程序的兩次運(yùn)行結(jié)果如圖 8-5 所示。 圖 8-5 MyException類的兩次運(yùn)行結(jié)果 在這個程序中,定義的異常類通過 extends 子句繼承了 Exception 異常類。在 test( ) 方法中,用 throw 語句指定了可能拋出的異常,該語句在參數(shù)小于 0 時(shí)被執(zhí)行,產(chǎn)生并拋出異常 。 值得注意的是:在一個方法定義中如果采用了 throw 語句直接拋出異常,則該方法在發(fā)生異常的情況下可能沒有返回值。本例就屬于這種情況。 從本例也可以看出:由于系統(tǒng)不能識別用戶自定義的異常,所以需要編程人員在程序中的合適位置創(chuàng)建自定義異常的對象,并利用 throw 語句將這個新異常對象拋出。 2.間接拋出異常在 Java 程序中,可以在方法的定義中利用 throws 關(guān)鍵字聲明異常類型而間接拋出異常。也就是說,當(dāng) Java 程序中方法本身對其中出現(xiàn)的異常并不關(guān)心或不方便處理時(shí),可以不在方法實(shí)現(xiàn)中直接捕獲有關(guān)異常并進(jìn)行處理,而是在方法定義的時(shí)候通過 throws 關(guān)鍵字,將異常拋給上層調(diào)用處理。其形式如下。 public void myMethod1() throws IndexOutOfBoundsException { …… } 或 public void myMethod2() throws myException1, myException2 { …… } 在上層調(diào)用該方法時(shí),必須捕獲有關(guān)異常,否則編譯時(shí)將會出錯。例如,調(diào)用方法 myMethod2() 時(shí),必須按如下方式進(jìn)行。 try{ myMethod2 }catch (MyExceptionl e1){ …… }catch(MyException2 e2){ …… } 【例 8-6 】 帶有間接拋出異常的類。 public class OutOfRangeException extends Exception{ public OutOfRangeException(){}; public OutOfRangeException(Sting s){ super(s); } } // 定義一個異常類 import OutOfRangeException; //裝載異常類 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)建一個異常對象并可能拋出它 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 } } 這個例子有兩個特征,一是它利用了自定義的異常類 OutOfRangeException ,一旦程序執(zhí)行違背了所定義的邏輯就拋出這個異常;二是在拋出異常的方法中,利用 throws 關(guān)鍵字聲明了 OutOfRangeException 異常類的間接拋出,這樣若是在其他地方使用到這個類的對象,也可以捕獲這個異常。 使用 throws 子句拋出異常時(shí)應(yīng)注意如下兩個問題。 · 一般這種拋出異常的語句應(yīng)該被定義為在滿足一定條件時(shí)執(zhí)行,例如把 throws子句放在 if語句的條件分支中,只有當(dāng)條件得到滿足,即用戶定義的邏輯錯誤發(fā)生時(shí)才拋出。例如,例 8-6中的條件( value < MIN || value > MAX)滿足時(shí),拋出異常。 · 對于含有 throws子句的方法,應(yīng)該在方法頭定義中增加如下部分。 throws異常類名列表 這樣做主要是為了通知所有欲調(diào)用此方法的方法:由于該方法包含 throws了句,所以要準(zhǔn)備接受和處理它在運(yùn)行過程中可能會拋出的異常。如果方法中的 throws了句不止一個,方法頭的異常類名表中的列出的異常也不止一個,應(yīng)該包含所有可能產(chǎn)生的異常。例如,在上面的 myMethod2( ) 方法中包含的異常有: myException1 和 myException2 。 注意: 執(zhí)行 throws子語句將中斷程序的執(zhí)行,也就是說 throws的下一條語句將暫停執(zhí)行。 8.3.7 自定義異常類在實(shí)際的編程中并不一定非要使用 Java 已經(jīng)定義的異常,經(jīng)常需要創(chuàng)建自己的異常,以便指出編寫的代碼可能生成的一個特殊錯誤。創(chuàng)建自己的異常類,必須從一個現(xiàn)有的異常類型(最終繼承自 Throwable 類)繼承。繼承一個異常同繼承一個普通的類的方法是一樣的 。 Java 提供的一些異常有時(shí)候不能滿足編程的需求,例如規(guī)定用戶輸入數(shù)據(jù)的范圍在 20 到 30 之間,但是 Java 并沒有這個方面的異常,這時(shí)就可以應(yīng)用自定義的異常來規(guī)范化客戶的數(shù)據(jù)輸入。 在 Java 中進(jìn)行自定義異常時(shí),自定義異常類必須是 Throwable 類的直接或間接子類。下面的例子是關(guān)于自定義異常的。它通過繼承 Exception 類而繼承 Throwable 類,即間接繼承 Throwable 類。 【例 8-7 】 自定義異常類程序示例。 class OutBoundsException extends Exception { OutBoundsException (String mes) { // 調(diào)用超類的構(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é)果 注意: 一個方法所聲明拋棄的異常是作為這個方法與外界交互的一部分而存在的。 所以,方法的調(diào)用者必須了解這些異常,并確定如何正確地處理它們。 ---------------------------------------------------------------------------------------------------
<script></script> |
|