隨筆-61  評(píng)論-13  文章-19  trackbacks-0
          5.1.1·介紹

          什么是異常?在Java編程語言中,異常類定義程序中可能遇到的輕微
          的錯(cuò)誤條件??梢詫懘a來處理異常并繼續(xù)程序執(zhí)行,而不是讓程序
          中斷。在程序執(zhí)行中,任何中斷正常程序流程的異常條件就是錯(cuò)誤或
          ]異常。例如,發(fā)生下列情況時(shí),會(huì)出現(xiàn)異常:
          - 想打開的文件不存在
          - 網(wǎng)絡(luò)連接中斷
          - 受控操作數(shù)超出預(yù)定范圍
          - 非常感興趣地正在裝載的類文件丟失

          在Java編程語言中,錯(cuò)誤類定義被認(rèn)為是不能恢復(fù)的嚴(yán)重錯(cuò)誤條件。在
          大多數(shù)情況下,當(dāng)遇到這樣的錯(cuò)誤時(shí),建議讓程序中斷。Java編程語言
          實(shí)現(xiàn)C++異常來幫助建立彈性代碼。在程序中發(fā)生錯(cuò)誤時(shí),發(fā)現(xiàn)錯(cuò)誤的
          方法能拋出一個(gè)異常到其調(diào)用程序,發(fā)出已經(jīng)發(fā)生問題的信號(hào)。然后,
          調(diào)用方法捕獲拋出的異常,在可能時(shí),再恢復(fù)回來。這個(gè)方案給程序員
          一個(gè)寫處理程序的選擇,來處理異常。通過瀏覽API,可以決定方法拋出
          的是什么樣的異常。

          5.1.2·實(shí)例

          考慮一下HelloWorld.java程序版本的簡單擴(kuò)展,它通過信息來循環(huán):
          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. }

          正常情況下,當(dāng)異常被拋出時(shí),在其循環(huán)被執(zhí)行四次之后,程序終止,并帶有
          錯(cuò)誤信息,就象前面所示的程序那樣。
          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)

          異常處理允許程序捕獲異常,處理它們,然后繼續(xù)程序執(zhí)行。它是分層把關(guān),
          因此,錯(cuò)誤情況不會(huì)介入到程序的正常流程中。特殊情況發(fā)生時(shí),在與正常
          執(zhí)行的代碼分離的代碼塊中被處理。這就產(chǎn)生了更易識(shí)別和管理的代碼。

          5.2·異常處理

          Java編程語言提供了一個(gè)來考慮哪個(gè)異常被拋出以及如何來恢復(fù)它的機(jī)制。

          ·try和catch語句

          要處理特殊的異常,將能夠拋出異常的代碼放入try塊中,然后創(chuàng)建相應(yīng)的
          catch塊的列表,每個(gè)可以被拋出異常都有一個(gè)。如果生成的異常與catch
          中提到的相匹配,那么catch條件的塊語句就被執(zhí)行。在try塊之后,可能
          有許多catch塊,每一個(gè)都處理不同的異常。
          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·調(diào)用棧機(jī)制

          如果方法中的一個(gè)語句拋出一個(gè)沒有在相應(yīng)的try/catch塊中處理的異常,
          那么這個(gè)異常就被拋出到調(diào)用方法中。如果異常也沒有在調(diào)用方法中被處理,
          它就被拋出到該方法的調(diào)用程序。這個(gè)過程要一直延續(xù)到異常被處理。
          如果異常到這時(shí)還沒被處理,它便回到main(),而且,即使main()不處理它,
          那么,該異常就異常地中斷程序??紤]這樣一種情況,在該情況中main()
          方法調(diào)用另一個(gè)方法(比如,first()),然后它調(diào)用另一個(gè)
          (比如,second())。如果在second()中發(fā)生異常,那么必須做一個(gè)檢查
          來看看該異常是否有一個(gè)catch;如果沒有,那么對(duì)調(diào)用棧(first())中的
          下一個(gè)方法進(jìn)行檢查,然后檢查下一個(gè)(main())。如果這個(gè)異常在該
          調(diào)用棧上沒有被最后一個(gè)方法處理,那么就會(huì)發(fā)生一個(gè)運(yùn)行時(shí)錯(cuò)誤,
          程序終止執(zhí)行。

          5.2.2·finally語句

          finally語句定義一個(gè)總是執(zhí)行的代碼塊,而不考慮異常是否被捕獲。
          下述樣板代碼來自Frank Yellin弗蘭克葉林的白皮書《Java中的低級(jí)安全》:
          1. try {
          2. startFaucet();
          3. waterLawn();
          4. }
          5. finally {
          6. stopFaucet();
          7. }

          在前面的例子中,即使異常在打開開關(guān)或給草地澆水時(shí)發(fā)生,開關(guān)也能被關(guān)掉。
          try 后面的括號(hào)中的代碼被稱做保護(hù)碼。如果終止程序的System.exit()
          方法在保護(hù)碼內(nèi)被執(zhí)行,那么,這是finally語句不被執(zhí)行的唯一情況。
          這就暗示,控制流程能偏離正常執(zhí)行順序,比如,如果一個(gè)return語句
          被嵌入try塊內(nèi)的代碼中,那么,finally塊中的代碼應(yīng)在return前執(zhí)行。

          5.2.3·重訪前例

          下面的例子是第169頁main()方法的重寫。本程序以前的版本中產(chǎn)生的
          異常被捕獲,數(shù)組索引重新設(shè)定,使下述程序繼續(xù)運(yùn)行。
          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()

          當(dāng)循環(huán)被執(zhí)行時(shí),下述在屏幕上出現(xiàn)的信息將改變。

          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類充當(dāng)所有
          對(duì)象的父類,可以使用異常處理機(jī)制將這些對(duì)象拋出并捕獲。在Throwable
          類中定義方法來檢索與異常相關(guān)的錯(cuò)誤信息,并打印顯示異常發(fā)生的棧
          跟蹤信息。它有Error和Exception兩個(gè)基本子類.
          Throwable類不能使用,而使用子類異常中的一個(gè)來描述任何特殊異常。
          每個(gè)異常的目的描述如下:
          - Error表示恢復(fù)不是不可能但很困難的情況下的一種嚴(yán)重問題。比如說
          內(nèi)存溢出。不可能指望程序能處理這樣的情況。
          - RuntimeException表示一種設(shè)計(jì)或?qū)崿F(xiàn)問題。也就是說,它表示如果
          程序運(yùn)行正常,從不會(huì)發(fā)生的情況。比如,如果數(shù)組索引擴(kuò)展不超出
          數(shù)組界限,那么,ArrayIndexOutOfBoundsException異常從不會(huì)拋出。
          比如,這也適用于取消引用一個(gè)空值對(duì)象變量。因?yàn)橐粋€(gè)正確設(shè)計(jì)和
          實(shí)現(xiàn)的程序從不出現(xiàn)這種異常,通常對(duì)它不做處理。這會(huì)導(dǎo)致一個(gè)
          運(yùn)行時(shí)信息,應(yīng)確保能采取措施更正問題,而不是將它藏到誰也不
          注意的地方。
          - 其它異常表示一種運(yùn)行時(shí)的困難,它通常由環(huán)境效果引起,可以進(jìn)行
          處理。例子包括文件未找到或無效URL異常(用戶打了一個(gè)錯(cuò)誤的URL),
          如果用戶誤打了什么東西,兩者都容易出現(xiàn)。這兩者都可能因?yàn)橛脩?
          錯(cuò)誤而出現(xiàn),這就鼓勵(lì)程序員去處理它們。

          5.4·共同異常

          Java編程語言提供幾種預(yù)定義的異常。下面是可能遇到的更具共同性的
          異常中的幾種:

          - ArithmeticException—整數(shù)被0除,運(yùn)算得出的結(jié)果。
          - int I =12 / 0;
          - NullPointerException—當(dāng)對(duì)象沒被實(shí)例化時(shí),訪問對(duì)象的屬性或
          方法的嘗試:
          - Date d= null;
          - System.out.println(d.toString());
          - NegativeArraySizeException—?jiǎng)?chuàng)建帶負(fù)維數(shù)大小的數(shù)組的嘗試。
          - ArrayIndexoutofBoundsException—訪問超過數(shù)組大小范圍的一個(gè)元
          素的嘗試。
          - SecurityException—典型地被拋出到瀏覽器中,SecurityManager類將
          拋出applets的一個(gè)異常,該異常企圖做下述工作(除非明顯地得到允許):
          - 訪問一個(gè)本地文件
          - 打開主機(jī)的一個(gè)socket,這個(gè)主機(jī)與服務(wù)于applet的主機(jī)不是同一個(gè)。
          - 在運(yùn)行時(shí)環(huán)境中執(zhí)行另一個(gè)程序

          5.5·處理或聲明規(guī)則

          為了寫出健壯的代碼,Java編程語言要求,當(dāng)一個(gè)方法在棧(即,它已經(jīng)被
          調(diào)用)上發(fā)生Exception(它與Error或RuntimeException不同)時(shí),那么,
          該方法必須決定如果出現(xiàn)問題該采取什么措施。程序員可以做滿足該要求
          的兩件事:

          第一,通過將Try{}catch(){}塊納入其代碼中,在這里捕獲給被
          命名為屬于某個(gè)超類的異常,并調(diào)用方法處理它。即使catch塊是空的,
          這也算是處理情況。
          第二,讓被調(diào)用的方法表示它將不處理異常,而且該異常將被拋回到它所
          遇到的調(diào)用方法中。它是按如下所示通過用throws子句標(biāo)記的該調(diào)用方法
          的聲明來實(shí)現(xiàn)的: public void troublesome() throws IOException
          關(guān)鍵字throws之后是所有異常的列表,方法可以拋回到它的調(diào)用程序中。
          盡管這里只顯示了一個(gè)異常,如果有成倍的可能的異常可以通過該方法
          被拋出,那么,可以使用逗號(hào)分開的列表。

          是選擇處理還是選擇聲明一個(gè)異常取決于是否給你自己或你的調(diào)用程序一個(gè)
          更合適的候選的辦法來處理異常。注—由于異常類象其它類一樣被組編到
          層次中,而且由于無論何時(shí)想要使用超類都必須使用子類, 因此,可以
          捕獲異?!敖M”并以相同的捕獲代碼來處理它們。例如,盡管
          IOExceptions(EOFException,FileNotFoundException等等)
          有幾種不同的類型,通過俘獲IOException,也可以捕獲
          IOException任何子類的實(shí)例。

          5.6·創(chuàng)建自己的異常

          5.6.1·介紹

          用戶定義異常是通過擴(kuò)展Exception類來創(chuàng)建的。這種異常類可以包含
          一個(gè)“普通”類所包含的任何東西。下面就是一個(gè)用戶定義異常類例子,
          它包含一個(gè)構(gòu)造函數(shù)、幾個(gè)變量以及方法:

          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. }

          使用語句來拋出已經(jīng)創(chuàng)建的異常:
          throw new ServerTimedOutException
          ("Could not connect", 80);

          5.6.2·實(shí)例

          考慮一個(gè)客戶服務(wù)器程序。在客戶代碼中,要與服務(wù)器連接,并希望
          服務(wù)器在5秒鐘內(nèi)響應(yīng)。如果服務(wù)器沒有響應(yīng),那么,代碼就如下所述
          拋出一個(gè)異常(如一個(gè)用戶定義的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塊可以如前例所述那樣被嵌套。

          也可能部分地處理一個(gè)異常然后也將它拋出。如:
          try {
          .....
          .....
          } catch (ServerTimedOutException e) {
          System.out.println("Error caught ");
          throw e;
          }
          posted on 2006-03-19 22:56 xnabx 閱讀(242) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 荣成市| 萝北县| 土默特右旗| 腾冲县| 瓮安县| 绩溪县| 越西县| 邛崃市| 华坪县| 宁安市| 昌邑市| 称多县| 上饶市| 呼玛县| 沂南县| 青冈县| 怀来县| 日土县| 青海省| 格尔木市| 张掖市| 五寨县| 昂仁县| 凌云县| 万源市| 汝州市| 赣州市| 碌曲县| 高唐县| 岳阳市| 万荣县| 武义县| 峨边| 穆棱市| 雅安市| 江城| 昆山市| 慈溪市| 胶南市| 本溪市| 通州市|