5.1.1·介紹
什么是異常?在Java編程語言中,異常類定義程序中可能遇到的輕微 的錯誤條件??梢詫懘a來處理異常并繼續程序執行,而不是讓程序 中斷。在程序執行中,任何中斷正常程序流程的異常條件就是錯誤或 ]異常。例如,發生下列情況時,會出現異常: - 想打開的文件不存在 - 網絡連接中斷 - 受控操作數超出預定范圍 - 非常感興趣地正在裝載的類文件丟失
在Java編程語言中,錯誤類定義被認為是不能恢復的嚴重錯誤條件。在 大多數情況下,當遇到這樣的錯誤時,建議讓程序中斷。Java編程語言 實現C++異常來幫助建立彈性代碼。在程序中發生錯誤時,發現錯誤的 方法能拋出一個異常到其調用程序,發出已經發生問題的信號。然后, 調用方法捕獲拋出的異常,在可能時,再恢復回來。這個方案給程序員 一個寫處理程序的選擇,來處理異常。通過瀏覽API,可以決定方法拋出 的是什么樣的異常。
5.1.2·實例
考慮一下HelloWorld.java程序版本的簡單擴展,它通過信息來循環: 1. public class HelloWorld { 2. public static void main (String args[]) { 3. int i = 0; 4. 5. String greetings [] = { 6. "Hello world!", 7. "No, I mean it!", 8. "HELLO WORLD!!" 9. }; 10. 11. while (i < 4) { 12. System.out.println (greetings[i]); 13. i++; 14. } 15. } 16. }
正常情況下,當異常被拋出時,在其循環被執行四次之后,程序終止,并帶有 錯誤信息,就象前面所示的程序那樣。 1. c:\student\> java HelloWorld 2. Hello world! 3. No, I mean it! 4. HELLO WORLD!! 5. java.lang.ArrayIndexOutOfBoundsException: 3 6. at HelloWorld.main(HelloWorld.java:12)
異常處理允許程序捕獲異常,處理它們,然后繼續程序執行。它是分層把關, 因此,錯誤情況不會介入到程序的正常流程中。特殊情況發生時,在與正常 執行的代碼分離的代碼塊中被處理。這就產生了更易識別和管理的代碼。
5.2·異常處理
Java編程語言提供了一個來考慮哪個異常被拋出以及如何來恢復它的機制。
·try和catch語句
要處理特殊的異常,將能夠拋出異常的代碼放入try塊中,然后創建相應的 catch塊的列表,每個可以被拋出異常都有一個。如果生成的異常與catch 中提到的相匹配,那么catch條件的塊語句就被執行。在try塊之后,可能 有許多catch塊,每一個都處理不同的異常。 1. try { 2. // code that might throw a particular exception 3. } catch (MyExceptionType e) { 4. // code to execute if a MyExceptionType exception is thrown 5. } catch (Exception e) { 6. // code to execute if a general Exception exception is thrown 7. }
5.2.1·調用棧機制
如果方法中的一個語句拋出一個沒有在相應的try/catch塊中處理的異常, 那么這個異常就被拋出到調用方法中。如果異常也沒有在調用方法中被處理, 它就被拋出到該方法的調用程序。這個過程要一直延續到異常被處理。 如果異常到這時還沒被處理,它便回到main(),而且,即使main()不處理它, 那么,該異常就異常地中斷程序??紤]這樣一種情況,在該情況中main() 方法調用另一個方法(比如,first()),然后它調用另一個 (比如,second())。如果在second()中發生異常,那么必須做一個檢查 來看看該異常是否有一個catch;如果沒有,那么對調用棧(first())中的 下一個方法進行檢查,然后檢查下一個(main())。如果這個異常在該 調用棧上沒有被最后一個方法處理,那么就會發生一個運行時錯誤, 程序終止執行。
5.2.2·finally語句
finally語句定義一個總是執行的代碼塊,而不考慮異常是否被捕獲。 下述樣板代碼來自Frank Yellin弗蘭克葉林的白皮書《Java中的低級安全》: 1. try { 2. startFaucet(); 3. waterLawn(); 4. } 5. finally { 6. stopFaucet(); 7. }
在前面的例子中,即使異常在打開開關或給草地澆水時發生,開關也能被關掉。 try 后面的括號中的代碼被稱做保護碼。如果終止程序的System.exit() 方法在保護碼內被執行,那么,這是finally語句不被執行的唯一情況。 這就暗示,控制流程能偏離正常執行順序,比如,如果一個return語句 被嵌入try塊內的代碼中,那么,finally塊中的代碼應在return前執行。
5.2.3·重訪前例
下面的例子是第169頁main()方法的重寫。本程序以前的版本中產生的 異常被捕獲,數組索引重新設定,使下述程序繼續運行。 1. public static void main (String args[]) { 2. int i = 0; 3. String greetings [] = { 4. "Hello world!", 5. "No, I mean it!", 6. "HELLO WORLD!!" 7. }; 8. while (i < 4) { 9. try { 10. System.out.println (greetings[i]); 11. } catch (ArrayIndexOutOfBoundsException e){ 12. System.out.println( "Re-setting Index Value"); 13. i = -1; 14. } finally { 15. System.out.println("This is always printed"); 16. } 17. i++; 18. } // end while() 19. } // end main()
當循環被執行時,下述在屏幕上出現的信息將改變。
1. Hello world! 2. This is always printed 3. No, I mean it! 4. This is always printed 5. HELLO WORLD!! 6. This is always printed 7. Re-setting Index Value 8. This is always printed
5.3·異常分類
在Java編程語言中,異常有三種分類。Java.lang.Throwable類充當所有 對象的父類,可以使用異常處理機制將這些對象拋出并捕獲。在Throwable 類中定義方法來檢索與異常相關的錯誤信息,并打印顯示異常發生的棧 跟蹤信息。它有Error和Exception兩個基本子類. Throwable類不能使用,而使用子類異常中的一個來描述任何特殊異常。 每個異常的目的描述如下: - Error表示恢復不是不可能但很困難的情況下的一種嚴重問題。比如說 內存溢出。不可能指望程序能處理這樣的情況。 - RuntimeException表示一種設計或實現問題。也就是說,它表示如果 程序運行正常,從不會發生的情況。比如,如果數組索引擴展不超出 數組界限,那么,ArrayIndexOutOfBoundsException異常從不會拋出。 比如,這也適用于取消引用一個空值對象變量。因為一個正確設計和 實現的程序從不出現這種異常,通常對它不做處理。這會導致一個 運行時信息,應確保能采取措施更正問題,而不是將它藏到誰也不 注意的地方。 - 其它異常表示一種運行時的困難,它通常由環境效果引起,可以進行 處理。例子包括文件未找到或無效URL異常(用戶打了一個錯誤的URL), 如果用戶誤打了什么東西,兩者都容易出現。這兩者都可能因為用戶 錯誤而出現,這就鼓勵程序員去處理它們。
5.4·共同異常
Java編程語言提供幾種預定義的異常。下面是可能遇到的更具共同性的 異常中的幾種:
- ArithmeticException—整數被0除,運算得出的結果。 - int I =12 / 0; - NullPointerException—當對象沒被實例化時,訪問對象的屬性或 方法的嘗試: - Date d= null; - System.out.println(d.toString()); - NegativeArraySizeException—創建帶負維數大小的數組的嘗試。 - ArrayIndexoutofBoundsException—訪問超過數組大小范圍的一個元 素的嘗試。 - SecurityException—典型地被拋出到瀏覽器中,SecurityManager類將 拋出applets的一個異常,該異常企圖做下述工作(除非明顯地得到允許): - 訪問一個本地文件 - 打開主機的一個socket,這個主機與服務于applet的主機不是同一個。 - 在運行時環境中執行另一個程序
5.5·處理或聲明規則
為了寫出健壯的代碼,Java編程語言要求,當一個方法在棧(即,它已經被 調用)上發生Exception(它與Error或RuntimeException不同)時,那么, 該方法必須決定如果出現問題該采取什么措施。程序員可以做滿足該要求 的兩件事:
第一,通過將Try{}catch(){}塊納入其代碼中,在這里捕獲給被 命名為屬于某個超類的異常,并調用方法處理它。即使catch塊是空的, 這也算是處理情況。 第二,讓被調用的方法表示它將不處理異常,而且該異常將被拋回到它所 遇到的調用方法中。它是按如下所示通過用throws子句標記的該調用方法 的聲明來實現的: public void troublesome() throws IOException 關鍵字throws之后是所有異常的列表,方法可以拋回到它的調用程序中。 盡管這里只顯示了一個異常,如果有成倍的可能的異常可以通過該方法 被拋出,那么,可以使用逗號分開的列表。
是選擇處理還是選擇聲明一個異常取決于是否給你自己或你的調用程序一個 更合適的候選的辦法來處理異常。注—由于異常類象其它類一樣被組編到 層次中,而且由于無論何時想要使用超類都必須使用子類, 因此,可以 捕獲異?!敖M”并以相同的捕獲代碼來處理它們。例如,盡管 IOExceptions(EOFException,FileNotFoundException等等) 有幾種不同的類型,通過俘獲IOException,也可以捕獲 IOException任何子類的實例。
5.6·創建自己的異常
5.6.1·介紹
用戶定義異常是通過擴展Exception類來創建的。這種異常類可以包含 一個“普通”類所包含的任何東西。下面就是一個用戶定義異常類例子, 它包含一個構造函數、幾個變量以及方法:
1. public class ServerTimedOutException extends Exception { 2. private String reason; 3. private int port; 4. public ServerTimedOutException (String reason,int port){ 5. this.reason = reason; 6. this.port = port; 7. } 8. public String getReason() { 9. return reason; 10. } 11. public int getPort() { 12. return port; 13. } 14. }
使用語句來拋出已經創建的異常: throw new ServerTimedOutException ("Could not connect", 80);
5.6.2·實例
考慮一個客戶服務器程序。在客戶代碼中,要與服務器連接,并希望 服務器在5秒鐘內響應。如果服務器沒有響應,那么,代碼就如下所述 拋出一個異常(如一個用戶定義的ServerTimedOutException)。
1. public void connectMe(String serverName) throws ServerTimedOutException { 2. int success; 3. int portToConnect = 80; 4. success = open(serverName, portToConnect); 5. if (success == -1) { 6. throw new ServerTimedOutException( 7. "Could not connect", 80); 8. } 9. }
要捕獲異常,使用try語句: 1. public void findServer() { 2. . . . 3. try { 4. connectMe(defaultServer); 5. } catch(ServerTimedOutException e) { 6. System.out.println("Server timed out, trying alternate"); 7. try { 8. connectMe(alternateServer); 9. } catch (ServerTimedOutException e1) { 10. System.out.println("No server currently available"); 11. } 12. } 13. .. . 注—try和catch塊可以如前例所述那樣被嵌套。
也可能部分地處理一個異常然后也將它拋出。如: try { ..... ..... } catch (ServerTimedOutException e) { System.out.println("Error caught "); throw e; }
|
posted on 2006-03-19 22:56
xnabx 閱讀(235)
評論(0) 編輯 收藏 所屬分類:
Java