從制造到創造
          軟件工程師成長之路
          posts - 292,  comments - 96,  trackbacks - 0

          9.1 Java異常處理機制概述

          主要考慮的兩個問題:(1)如何表示異常情況?(2)如何控制處理異常的流程?

          9.1.1 Java異常處理機制的優點

          Java語言按照面向對象的思想來處理異常,使得程序具有更好的可維護性。

          Java異常處理機制具有以下優點:
          • 把各種不同類型的異常情況進行分類,用Java類來表示異常情況,發揮類的可擴展性和可重用性。
          • 異常流程的代碼和正常流程的代碼分離,提供了程序的可讀性,簡化了程序的結構。
          • 可以靈活地處理異常,如果當前方法有能力處理異常,就捕獲并處理它,否則只需要拋出異常,由方法調用者來處理它。

          9.1.2 Java虛擬機的方法調用棧

          如果方法中的代碼塊可能拋出異常,有如下兩種處理方法:
          (1)在當前方法中通過try...catch語句捕獲并處理異常;
          (2)在方法的聲明處通過throws語句聲明拋出異常。
          當Java虛擬機追溯到調用棧的底部的方法時,如果仍然沒有找到處理該異常的代碼,將按以下步驟處理:
          (1)調用異常對象的printStachTrace()方法,打印來自方法調用棧的異常信息。
          (2)如果該線程不是主線程,那么終止這個線程,其它線程繼續正常運行。如果該線程是主線程,那么整個應用程序被終止。

          9.1.3 異常處理對性能的影響

          一般來說,影響很小,除非方法嵌套調用很深。

          9.2 運用Java異常處理機制

          9.2.1 try...catch語句:捕獲異常

          9.2.2 finally語句:任何情況下都必須執行的代碼

          主要用于關閉某些流和數據庫連接。

          9.2.3 thorws子句:聲明可能會出現的異常

          9.2.4 throw語句:拋出異常

          9.2.5 異常處理語句的語法規則

          (1)try代碼塊不能脫離catch代碼塊或finally代碼塊而單獨存在。try代碼塊后面至少有一個catch代碼塊或finally代碼塊。
          (2)try代碼塊后面可以有零個或多個catch代碼塊,還可以有零個或至多一個finally代碼塊。
          (3)try代碼塊后面可以只跟finally代碼塊。
          (4)在try代碼塊中定義的變量的作用域為try代碼塊,在catch代碼塊和finally代碼塊中不能訪問該變量。
          (5)當try代碼塊后面有多個catch代碼塊時,Java虛擬機會把實際拋出的異常類對象依次和各個catch代碼塊聲明的異常類型匹配,如果異常對象為某個異常類型或其子類的實例,就執行這個catch代碼塊,而不會再執行其他的catch代碼塊。
          (6)如果一個方法可能出現受檢查異常,要么用try...catch語句捕獲,要么用throws子句聲明將它拋出,否則會導致編譯錯誤。

          9.2.6 異常流程的運行過程

          (1)finally語句不被執行的唯一情況是先執行了用于終止程序的System.exit()方法。
          (2)return語句用于退出本方法。
          (3)finally代碼塊雖然在return語句之前被執行,但finally代碼塊不能通過重新給變量賦值來改變return語句的返回值。
          (4)建議不要在finally代碼塊中使用return語句,因為它會導致以下兩種潛在的錯誤
                   A:覆蓋try或catch代碼塊的return語句
          public class SpecialException extends Exception {
              
          public SpecialException() {

              }

              
          public SpecialException(String msg) {
                  
          super(msg);
              }
          }

          public class FinallyReturn {

              
          /**
               * 
          @param args
               
          */
              
          public static void main(String[] args) {
                  FinallyReturn fr 
          = new FinallyReturn();
                  System.out.println(fr.methodB(
          1));// 打印100
                  System.out.println(fr.methodB(2));// 打印100
              }

              
          public int methodA(int money) throws SpecialException {
                  
          if (--money <= 0) {
                      
          throw new SpecialException("Out of money");
                  }

                  
          return money;
              }

              @SuppressWarnings(
          "finally")
              
          public int methodB(int money) {
                  
          try {
                      
          return methodA(money);// 可能拋出異常
                  } catch (SpecialException e) {
                      
          return -100;
                  } 
          finally {
                      
          return 100;// 會覆蓋try和catch代碼塊的return語句
                  }
              }

          }

                  B:丟失異常
          public class ExLoss {

              
          /**
               * 
          @param args
               
          */
              
          public static void main(String[] args) {
                  
          try {
                      System.out.println(
          new ExLoss().methodB(1));// 打印100
                      System.out.println("No Exception");
                  } 
          catch (Exception e) {
                      System.out.println(e.getMessage());
                  }
              }

              
          public int methodA(int money) throws SpecialException {
                  
          if (--money <= 0) {
                      
          throw new SpecialException("Out of money");
                  }

                  
          return money;
              }

              @SuppressWarnings(
          "finally")
              
          public int methodB(int money) {
                  
          try {
                      
          return methodA(money);// 可能拋出異常
                  } catch (SpecialException e) {
                      
          throw new Exception("Wrong");
                  } 
          finally {
                      
          return 100;// 會丟失catch代碼塊中的異常
                  }
              }
          }

          9.3 Java異常類

          所有異常類的祖先類為java.lang.Throwable類,它的實例表示具體的異常對象,可以通過throw語句拋出。

          Throwable類提供了訪問異常信息的一些方法,常用的方法包括:
          • getMessage() --返回String類型的異常信息。
          • printStachTrace()--打印跟蹤方法調用棧而獲得的詳細異常信息。在程序調試階段,此方法可用于跟蹤錯誤。
          public class ExTrace {

              
          /**
               * 
          @param args
               
          */
              
          public static void main(String[] args) {
                  
          try {
                      
          new ExTrace().methodB(1);
                  } 
          catch (Exception e) {
                      System.out.println(
          "--- Output of main() ---");
                      e.printStackTrace();
                  }
              }

              
          public void methodA(int money) throws SpecialException {
                  
          if (--money <= 0) {
                      
          throw new SpecialException("Out of money");
                  }
              }

              
          public void methodB(int money) throws Exception {
                  
          try {
                      methodA(money);    
                  } 
          catch (SpecialException e) {
                      System.out.println(
          "--- Output of methodB() ---");
                      System.out.println(e.getMessage());
                      
          throw new Exception("Wrong");
                  }
              }
          }

          打印結果:
          --- Output of methodB() ---
          Out of money
          --- Output of main() ---
          java.lang.Exception: Wrong
              at chapter09.d0903.ExTrace.methodB(ExTrace.java:
          45)
              at chapter09.d0903.ExTrace.main(ExTrace.java:
          26)

          Throwable類有兩個直接子類:
          • Error類--表示僅靠程序本身無法恢復的嚴重錯誤,如內存不足等。
          • Exception類--表示程序本身可以處理的異常。

          9.3.1 運行時異常

          RuntimeException類及其子類都被稱為運行時異常,這種異常的特點是Java編譯器不會檢查它,會編譯通過,但運行時如果條件成立就會出現異常。

          例如當以下divided()方法的參數b為0,執行“a/b”操作時會出現ArrithmeticException異常,它屬于運行時異常,Java編譯器不會檢查它。

              public int divide2(int a, int b) {
                  
          return a / b;// 當參數為0,拋出ArrithmeticException
              }
          下面的程序中的IllegalArgumentException也是運行時異常,divided()方法即沒有捕獲它,也沒有聲明拋出它。
          public class WithRuntimeEx {

              
          /**
               * @param args
               
          */
              
          public static void main(String[] args) {
                  new WithRuntimeEx().divide(
          10);
                  System.out.println("
          End");
              }

              
          public int divide(int a, int b) {
                  
          if (b == 0) {
                      throw new IllegalArgumentException("除數不能為0");
                  }

                  
          return a / b;
              }

          }

          由于程序代碼不會處理運行時異常,因此當程序在運行時出現了這種異常時,就會導致程序異常終止。以上程序的打印結果為:
          Exception in thread "main" java.lang.IllegalArgumentException: 除數不能為0
              at chapter09.d0903.WithRuntimeEx.divide(WithRuntimeEx.java:
          29)
              at chapter09.d0903.WithRuntimeEx.main(WithRuntimeEx.java:
          23)

          9.3.2 受檢查異常

          除了RuntimeException及其子類以外,其他的Exception類及其子類都屬于受檢查異常(Checked Exception)。這種異常要么catch語句捕獲,要么throws子句聲明拋出,否則編譯出錯。

          9.3.3 區分運行時異常和受檢查異常

          受檢查異常表示程序可以處理的異常。

          運行時異常表示無法讓程序恢復運行的異常,導致這種異常的原因通常是由于執行了錯誤操作。一旦出現了錯誤操作,建議終止程序,因此Java編譯器不檢查這種異常。

          9.3.4 區分運行時異常和錯誤

          Error類及其子類表示程序本身無法修復的錯誤,它和運行時異常的相同之處是:Java編譯器都不會檢查它們,當程序運行時出現它們,都會終止程序。

          兩者的不同之處是:Error類及其子類表示的錯誤通常是由Java虛擬機拋出。

          而RuntimeException類表示程序代碼中的錯誤,它是可擴展的,用戶可以根據特定的問題領域來創建相關的運行時異常類。

          9.4 用戶定義異常

          9.4.1 異常轉譯和異常鏈

          public class BaseException extends Exception {

              
          protected Throwable cause = null;

              
          public BaseException() {

              }

              
          public BaseException(String msg) {
                  
          super(msg);
              }

              
          public BaseException(Throwable cause) {
                  
          this.cause = cause;
              }

              
          public BaseException(String msg, Throwable cause) {
                  
          super(msg);
                  
          this.cause = cause;
              }

              
          public Throwable initCause(Throwable cause) {
                  
          this.cause = cause;
                  
          return this;
              }

              
          public Throwable getCause() {
                  
          return cause;
              }

              
          public void printStackTrace() {
                  printStackTrace(System.err);
              }

              
          public void printStackTrace(PrintStream outStream) {
                  printStackTrace(
          new PrintStream(outStream));
              }

              
          public void printStackTrace(PrintWriter writer) {
                  
          super.printStackTrace(writer);

                  
          if (getCause() != null) {
                      getCause().printStackTrace(writer);
                  }

                  writer.flush();
              }
          }

          9.4.2 處理多樣化異常

          public class MultiBaseException extends Exception {

              
          protected Throwable cause = null;

              
          private List<Throwable> exceptions = new ArrayList<Throwable>();

              
          public MultiBaseException() {

              }

              
          public MultiBaseException(Throwable cause) {
                  
          this.cause = cause;
              }

              
          public MultiBaseException(String msg, Throwable cause) {
                  
          super(msg);
                  
          this.cause = cause;
              }

              
          public List getException() {
                  
          return exceptions;
              }

              
          public void addException(MultiBaseException ex) {
                  exceptions.add(ex);
              }

              
          public Throwable initCause(Throwable cause) {
                  
          this.cause = cause;
                  
          return this;
              }

              
          public Throwable getCause() {
                  
          return cause;
              }

              
          public void printStackTrace() {
                  printStackTrace(System.err);
              }

              
          public void printStackTrace(PrintStream outStream) {
                  printStackTrace(
          new PrintStream(outStream));
              }

              
          public void printStackTrace(PrintWriter writer) {
                  
          super.printStackTrace(writer);

                  
          if (getCause() != null) {
                      getCause().printStackTrace(writer);
                  }

                  writer.flush();
              }
          }

          9.5 異常處理原則

          9.5.1 異常只能用于非正常情況

          9.5.2 為異常提供說明文檔

          9.5.3 盡可能地避免異常

          9.5.4 保持異常的原子性

          9.5.5 避免過于龐大的try代碼塊

          9.5.6 在catch子句中指定具體的異常類型

          9.5.7 不要在catch代碼塊中忽略被捕獲的異常,可以處理異常、重新拋出異常、進行異常轉譯

          posted on 2008-02-22 17:50 CoderDream 閱讀(889) 評論(0)  編輯  收藏 所屬分類: Java-14.Exception

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           

          <2008年2月>
          272829303112
          3456789
          10111213141516
          17181920212223
          2425262728291
          2345678

          常用鏈接

          留言簿(9)

          我參與的團隊

          隨筆分類(245)

          隨筆檔案(239)

          文章分類(3)

          文章檔案(3)

          收藏夾(576)

          友情鏈接

          搜索

          •  

          積分與排名

          • 積分 - 458376
          • 排名 - 114

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 五莲县| 静海县| 邛崃市| 定安县| 马公市| 东辽县| 宜春市| 扎赉特旗| 桐柏县| 钟祥市| 尼勒克县| 定远县| 富裕县| 阿勒泰市| 平顶山市| 临泉县| 白水县| 昭平县| 大兴区| 塔城市| 青田县| 卢龙县| 龙游县| 永登县| 牙克石市| 驻马店市| 内丘县| 淮北市| 咸宁市| 晴隆县| 普安县| 五家渠市| 沭阳县| 吉首市| 利川市| 广元市| 濮阳市| 石首市| 承德市| 班玛县| 大埔县|