thinking

          one platform thousands thinking

          如何避免在Java中使用Checked Exception

          如何避免在Java中使用Checked Exception


          發(fā)布時間:2007.08.20 08:52     來源:賽迪網(wǎng)    作者:dxaw

          這 篇文章指出了Java中checked Exception的一些缺點(diǎn),提出應(yīng)該在程序設(shè)計(jì)中避免使用checked Exception,對于需要處理checked Exception的代碼,可以使用ExceptionAdapter這個類對checked Exception進(jìn)行包裝。這篇文章的概念和ExceptionAdapter這個類均源自Bruce Eckel的Does Java need Checked Exception。

          Java的Exception分為兩類,一類是RuntimeException及 其子類,另外一類就是checked Exception。Java要求函數(shù)對沒有被catch處理掉的checked Exception,需要將其寫在函數(shù)的聲明部分。然而,這一要求常常給程序員帶來一些不必要的負(fù)擔(dān)。

          為了避免在函數(shù)聲明中寫throws部分,在Java項(xiàng)目里面常常可以看到以下代碼用來‘吞掉’Exception:

          try {



          // ...



          } catch (Exception ex) {



          ex.printStackTrace();



          }

          這顯然不是一個好的處理Exception辦法,事實(shí)上,catch并處理一個Exception意味著讓程序從發(fā)生的錯誤(Exception)中恢復(fù)過來。從這種意義上說,已上的代碼只可能在一些很簡單的情況下工作而不帶來問題。

          對于很多Exception,往往沒有去處理它并讓程序從錯誤中恢復(fù)出來的辦法,這 時唯一能做的事情可能就是在界面上顯示一些提示信息給用戶。這種情況下讓程序拋出遇到的Exception是更為合理的做法。然而,這樣做會使得一些函數(shù) 的聲明急劇膨脹。一個函數(shù)可能需要聲明會拋出的7、8個checked Exception,而且每個調(diào)用它的函數(shù)也需要同樣的聲明。

          比這更糟糕的是,這有可能破壞類設(shè)計(jì)的open-close原則。簡單來 說,open-close原則是指當(dāng)擴(kuò)展一個模塊的時候,可以不影響其現(xiàn)有的client。open-close原則是通過繼承來實(shí)現(xiàn)的,當(dāng)繼承一個類的 時候,我們既擴(kuò)展了這個類,也不會影響原有的client(因?yàn)閷@個類沒有改動)。

          現(xiàn)在考慮下面這種情況,有一個父類Base:

          public class Base {

          public void foo() throws ExceptionA {

          // ...

          }

          }

          現(xiàn)在需要繼承Base這個類并重載foo這個方法,在新的實(shí)現(xiàn)中,foo可能拋出ExceptionB:

          public class Extend extends Base {

          public void foo() throws ExceptionB {

          // ...

          }

          }

          然而,這樣寫在Java里面是不合法的,因?yàn)镴ava把可能會拋出的Exception看作函數(shù)特征的一部分,子類聲明拋出的Exception必須是父類的子集。

          可以在Base類的foo方法中加入拋出ExceptionB的聲明,然而,這樣就破壞了open-close原則。而且,有時我們沒有辦法去修改父類,比如當(dāng)重載一個Jdk里的類的時候。

          另一個可能的做法是在Extend的foo方法中catch住ExceptionB,然后構(gòu)造一個ExceptionA并拋出。這是個可行的辦法但也只是一個權(quán)宜之計(jì)。

          如果使用RuntimeException,這些問題都不會存在。這說明 checked Exception并不是一個很實(shí)用的概念,也意味著在程序設(shè)計(jì)的時候,我們應(yīng)該讓自己的Exception類繼承RuntimeException而不 是Exception。(這和JDK的建議正好相反,但實(shí)踐證明這樣做代碼的質(zhì)量更好。)

          對于那些需要處理checked Exception的代碼,可以利用一個ExceptionAdapter的類把checked Exception包裝成一個RuntimeException拋出。ExceptionAdapter來自Bruce Eckel的Does Java need Checked Exception這篇文章,在這里的ExceptionAdapter是我根據(jù)JDK 1.4修改過的:

          public class ExceptionAdapter extends RuntimeException {



          public ExceptionAdapter(Exception ex) {



          super(ex);

          }



          public void printStackTrace(java.io.PrintStream s) {



          getCause().printStackTrace(s);

          }



          public void printStackTrace(java.io.PrintWriter s) {



          getCause().printStackTrace(s);



          }



          // rethrow()的作用是把被包裝的Exception再次拋出。



          public void rethrow()

          throws Exception

          {

          throw (Exception) getCause();

          }



          }

          (責(zé)任編輯:編輯龔勛)

          posted on 2009-02-17 11:18 lau 閱讀(300) 評論(1)  編輯  收藏 所屬分類: J2SE

          Feedback

          # re: 如何避免在Java中使用Checked Exception 2010-11-15 18:43 lau

          Java里有個很重要的特色是Exception ,也就是說允許程序產(chǎn)生例外狀況。而在學(xué)Java 的時候,我們也只知道Exception 的寫法,卻未必真能了解不同種類的Exception 的區(qū)別。

            首先,您應(yīng)該知道的是Java 提供了兩種Exception 的模式,一種是執(zhí)行的時候所產(chǎn)生的Exception (Runtime Exception),另外一種則是受控制的Exception (Checked Exception)。

            所有的Checked Exception 均從java.lang.Exception 繼承而來,而Runtime Exception 則繼承java.lang.RuntimeException 或java.lang.Error (實(shí)際上java.lang.RuntimeException 的上一層也是java.lang.Exception)。

            當(dāng)我們撰寫程序的時候,我們很可能會對選擇某種形式的Exception 感到困擾,到底我應(yīng)該選擇Runtime Exception 還是Checked Exception ?

            其實(shí),在運(yùn)作上,我們可以通過Class 的Method 如何產(chǎn)生某個Exception以及某個程序如何處理這個被產(chǎn)生來的Exception 來了解它們之間的差異。
          首先我們先建立一個Exception

          public class CException extends Exception
          {
          public CException() {}
          public CException(String message)
          {
          super(message);
          }
          }

          然后我們撰寫一個可能產(chǎn)生 CException 的 Class

          public class testException
          {
          public void method1() throws CException
          {
          throw new CException("Test Exception");
          }

          public void method2(String msg)
          {
          if(msg == null)
          {
          throw new NullPointerException("Message is null");
          }
          }

          public void method3() throws CException
          {
          method1();
          }

          // 以下省略
          // ...
          }

            在這三個method 中,我們看到了method1 和method2 的程序碼內(nèi)都會產(chǎn)生Exception,但method3 的程序碼中(大括號內(nèi)),并沒產(chǎn)生Exception,但在method3 的定義中,暗示了這個method 可能產(chǎn)生CException。

          呼叫method1() 的程序,必須將method1() 包含在try 與catch 中,如:

          public class runtest
          {
          // ....
          public static void main(String argv[])
          {
          testException te = new testException();
          try
          {
          te.method1();
          }
          catch(CException ce)
          {
          // ....
          }
          }
          // ...
          }

            雖然包含在try 與catch 中,并不表示這段程序碼一定會收到CException,但它的用意在于提醒呼叫者,執(zhí)行這個method 可能產(chǎn)生的意外,而使用者也必須要能針對這個意外做出相對應(yīng)的處理方式。

            當(dāng)使用者呼叫method2() 時,并不需要使用try 和catch 將程序碼包起來,因?yàn)閙ethod2 的定義中,并沒有throws 任何的Exception ,如:

          public class runtest
          {
          // ....
          public static void main(String argv[])
          {

          testException te = new testException();

          // 不會產(chǎn)生 Exception
          te.method2("Hello");

          // 會產(chǎn)生 Exception
          te.method2(null);
          }
          // ...
          }

            程序在執(zhí)行的時候,也不見得會真的產(chǎn)生NullPointerException ,這種Exception 叫做runtime exception 也有人稱為unchecked exception ,產(chǎn)生Runtime Exception 的method (在這個范例中是method2) 并不需要在宣告method 的時候定義它將會產(chǎn)生哪一種Exception 。

          在testException 的method3() 中,我們看到了另外一種狀況,也就是method3里呼叫了method1() ,但卻沒有將method1 包在try 和catch 之間。相反,在method3() 的定義中,它定義了CException,實(shí)際上就是如果method3 收到了CException ,它將不處理這個CException ,而將它往外丟。當(dāng)然,由于method3 的定義中有throws CException ,因此呼叫method3 的程序碼也需要有try catch 才行。

            因此從程序的運(yùn)作機(jī)制上看,Runtime Exception與Checked Exception 不一樣,然而從邏輯上看,Runtime Exception 與Checked Exception 在使用的目的上也不一樣。

            一般而言,Checked Exception 表示這個Exception 必須要被處理,也就是說程序設(shè)計(jì)者應(yīng)該已經(jīng)知道可能會收到某個Exception(因?yàn)橐猼ry catch住) ,所以程序設(shè)計(jì)者應(yīng)該能針對這些不同的Checked Exception 做出不同的處理。

            而Runtime Exception 通常會暗示著程序上的錯誤,這種錯誤會導(dǎo)致程序設(shè)計(jì)者無法處理,而造成程序無法繼續(xù)執(zhí)行下去。

          看看下面的例子:

          String message[] = {"message1", "message2","message3"};
          System.out.println(message[3]);

            這段程序碼在Compile 時并沒問題,但在執(zhí)行時則會出現(xiàn)ArrayIndexOutOfBoundException 的例外,在這種狀況下,我們亦無法針對這個Runtime Exception 做出有意義的動作,這就像是我們呼叫了testException 中的method2 ,卻引發(fā)了它的NullPointerException 一樣,在這種狀況下,我們必須對程序碼進(jìn)行修改,從而避免這個問題。

            因此,實(shí)際上我們應(yīng)該也必須要去抓取所有的Checked Exception,同時最好能在這些Checked Exception 發(fā)生的時候做出相對應(yīng)的處理,好讓程序能面對不同的狀況。

          然而對于Runtime Exception ,有些人建議將它c(diǎn)atch 住,然后導(dǎo)向其它地方,讓程序繼續(xù)執(zhí)行下去,這種作法并非不好,但它會讓我們在某些測試工具下認(rèn)為我們的程序碼沒有問題,因?yàn)槲覀儗untime Exception "處理"掉了,事實(shí)卻不然!譬如很多人的習(xí)慣是在程序的進(jìn)入點(diǎn)后用個大大的try catch 包起來,如:

          public class runtest1
          {
          public static void main(String argv[])
          {
          try
          {
          //...
          }
          catch(Exception e)
          {
          }
          }
          }

            在這種情況下,我們很可能會不知道發(fā)生了什么Exception 或是從哪一行發(fā)出的,因此在面對不同的Checked Exception時,我們可已分別去try catch它。而在測試階段時,如果碰到Runtime Exception ,我們可以讓它就這樣發(fā)生,接著再去修改我們的程序碼,讓它避免Runtime Exception,否則,我們就應(yīng)該仔細(xì)追究每一個Exception ,直到我們可以確定它不會有Runtime Exception 為止!

            對于Checked Exception 與Runtime Exception ,我想應(yīng)該有不少人會有不同的觀點(diǎn),無論如何,程序先要能執(zhí)行,這些Exception 才有機(jī)會產(chǎn)生。因此,我們可以把這些Exception 當(dāng)成是Bug ,也可以當(dāng)成是不同的狀況(Checked Exception),或當(dāng)成是幫助我們除錯的工具(Runtime Exception),但前提是我們需要處理這些Exception ,如果不處理,那么問題或狀況就會永遠(yuǎn)留在那里。  回復(fù)  更多評論   

          主站蜘蛛池模板: 精河县| 宁国市| 东源县| 柳州市| 嘉义县| 冀州市| 宝应县| 宜黄县| 庐江县| 杭锦后旗| 兴城市| 通渭县| 光山县| 封开县| 和林格尔县| 平湖市| 前郭尔| 镇雄县| 龙江县| 嘉鱼县| 城市| 安阳市| 银川市| 东平县| 洛南县| 碌曲县| 高唐县| 安阳市| 武隆县| 和政县| 平山县| 临泉县| 瑞安市| 新沂市| 太湖县| 余姚市| 中超| 广安市| 扬州市| 周至县| 花垣县|