首頁 > Java > java教程 > java提高篇(十七)-----異常(二)

java提高篇(十七)-----異常(二)

黄舟
發布: 2017-02-10 11:45:30
原創
1067 人瀏覽過

          五、自訂異常       Java確實為我們提供了非常多的異常,但是異常體係是不可能預見所有的希望加以報告的錯誤,所以Java允許我們自訂異常來表現程式中可能會遇到的特定問題,總之就是一句話:我們不必拘泥於Java中已有的異常類型。

      

Java自訂異常的使用要經歷以下四個步驟:繼承Throwable或其子類別。

      2、添加構造方法(當然也可以不用添加,使用預設構造方法)。

      3、某方法類別中拋出此異常。

      4、捕捉此異常。

/** 自定义异常 继承Exception类 **/
public class MyException extends Exception{
    public MyException(){
        
    }
    
    public MyException(String message){
        super(message);
    }
}

public class Test {
    public void display(int i) throws MyException{
        if(i == 0){
            throw new MyException("该值不能为0.......");
        }
        else{
            System.out.println( i / 2);
        }
    }
    
    public static void main(String[] args) {
        Test test = new Test();
        try {
            test.display(0);
            System.out.println("---------------------");
        } catch (MyException e) {
            e.printStackTrace();
        }
    }
}
登入後複製
      

              六、異常鏈

      

      

在設計模式中有一個叫做責任鏈模式,該模式是將多個物件連結成一條鏈,客戶端的請求沿著這條鏈傳遞直到被接收、處理。同樣Java異常機制也提供了這樣一條鏈:異常鏈。

      


我們知道每遇到一個異常訊息,我們都需要進行try…catch,一個還好,如果出現多個異常呢?分類處理一定會比較麻煩,那就一個Exception解決所有的異常吧。這樣確實是可以,但是這樣處理勢必會導致後面的維護難度增加。最好的方法就是將這些異常訊息封裝,然後捕獲我們的封裝類別即可。

      

誠然在應用程式中,我們有時並不僅僅需要封裝異常,更需要傳遞。怎麼傳遞? throws!! binge,正確! !但如果僅僅只用throws拋出異常,那麼你的封裝類,怎麼辦? ?       

我們有兩種方式處理異常,一是throws拋出交給上級處理,二是try…catch做具體處理。但是這個跟上面有什麼關聯呢? try…catch的catch區塊我們可以不需要做任何處理,僅僅只用throw這個關鍵字將我們封裝異常訊息主動拋出。然後在透過關鍵字throws繼續拋出該方法異常。它的上層也可以做這樣的處理,以此類推就會產生一條由異常構成的異常鏈。

      

透過使用異常鏈,我們可以提高程式碼的可理解性、系統的可維護性和友善性。

同理,我们有时候在捕获一个异常后抛出另一个异常信息,并且希望将原始的异常信息也保持起来,这个时候也需要使用异常链。

在异常链的使用中,throw抛出的是一个新的异常信息,这样势必会导致原有的异常信息丢失,如何保持?在Throwable及其子类中的构造器中都可以接受一个cause参数,该参数保存了原有的异常信息,通过getCause()就可以获取该原始异常信息。

语法:

public void test() throws XxxException{
        try {
            //do something:可能抛出异常信息的代码块
        } catch (Exception e) {
            throw new XxxException(e);
        }
    }
登入後複製

示例:

public class Test {
    public void f() throws MyException{
         try {
            FileReader reader = new FileReader("G:\\myfile\\struts.txt");  
             Scanner in = new Scanner(reader);  
             System.out.println(in.next());
        } catch (FileNotFoundException e) {
            //e 保存异常信息
            throw new MyException("文件没有找到--01",e);
        }  
    }
    
    public void g() throws MyException{
        try {
            f();
        } catch (MyException e) {
            //e 保存异常信息
            throw new MyException("文件没有找到--02",e);
        }
    }
    
    public static void main(String[] args) {
        Test t = new Test();
        try {
            t.g();
        } catch (MyException e) {
            e.printStackTrace();
        }
    }
}
登入後複製


运行结果:

com.test9.MyException: 文件没有找到--02
    at com.test9.Test.g(Test.java:31)
    at com.test9.Test.main(Test.java:38)
Caused by: com.test9.MyException: 文件没有找到--01
    at com.test9.Test.f(Test.java:22)
    at com.test9.Test.g(Test.java:28)
    ... 1 more
Caused by: java.io.FileNotFoundException: G:\myfile\struts.txt (系统找不到指定的路径。)
    at java.io.FileInputStream.open(Native Method)
    at java.io.FileInputStream.<init>(FileInputStream.java:106)
    at java.io.FileInputStream.<init>(FileInputStream.java:66)
    at java.io.FileReader.<init>(FileReader.java:41)
    at com.test9.Test.f(Test.java:17)
    ... 2 more
登入後複製

如果在程序中,去掉e,也就是:throw new MyException("文件没有找到--02");

那么异常信息就保存不了,运行结果如下:

com.test9.MyException: 文件没有找到--02
    at com.test9.Test.g(Test.java:31)
    at com.test9.Test.main(Test.java:38)
登入後複製

PS:其实对于异常链鄙人使用的也不是很多,理解的不是很清楚,望各位指正!!!!

七、异常的使用误区

首先我们先看如下示例:该实例能够反映java异常的不正确使用(其实这也是我刚刚学Java时写的代码)!!

OutputStreamWriter out = null;
        java.sql.Connection conn = null;
        try {            //   ---------1
            Statement stat = conn.createStatement();
            ResultSet rs = stat.executeQuery("select *from user");
            while (rs.next()){
                out.println("name:" + rs.getString("name") + "sex:"
                        + rs.getString("sex"));
            }
            conn.close();         //------2
            out.close();
        } 
        catch (Exception ex){    //------3
            ex.printStackTrace();    //------4
        }
登入後複製


1、-----------1

对于这个try…catch块,我想他的真正目的是捕获SQL的异常,但是这个try块是不是包含了太多的信息了。这是我们为了偷懒而养成的代码坏习惯。有些人喜欢将一大块的代码全部包含在一个try块里面,因为这样省事,反正有异常它就会抛出,而不愿意花时间来分析这个大代码块有那几块会产生异常,产生什么类型的异常,反正就是一篓子全部搞定。这就想我们出去旅游将所有的东西全部装进一个箱子里面,而不是分类来装,虽不知装进去容易,找出来难啊!!!所有对于一个异常块,我们应该仔细分清楚每块的抛出异常,因为一个大代码块有太多的地方会出现异常了。

结论一:尽可能的减小try块!!!

2、--------2

      在這裡你發現了什麼?異常改變了運作流程! !不錯就是異常改變了程式運作流程。如果程式發生了異常那麼conn.close();out.close();是不可能執行得到的,這樣勢必會導致資源不能釋放掉。所以如果程式用到了檔案、Socket、JDBC連線之類的資源,即使遇到了異常,我們也要確保能夠正確釋放佔用的資源。這裡finally就有用武之地了:不管是否出現了異常,finally總是有機會運作的,所以finally用來釋放資源是再適合不過了。

      二:保證所有資源都會正確釋放。充分運用finally關鍵字。

           我認為大多數人對於這個程式碼是這樣處理的,(LZ也是)。使用這樣程式碼的人都有這樣一個心理,一個catch解決所有異常,這樣是可以,但不推薦!為什麼!首先我們要明白catch塊所表示是它預期會出現何種異常,並且需要做何種處理,而使用Exception就表示他要處理所有的異常信息,但是這樣做有什麼意義呢?

      這裡我們再來看看上面的程序實例,很明顯它可能需要拋出兩個異常信息,ExSQLException和IOException。所以一個catch處理兩個截然不同的Exception明顯的不合適。如果用兩個catch,一個處理SQLException、一個處理IOException就好多了。所以:

      

結論三類:catch語句應盡量指定為異常的類型,而不會涵蓋範圍太廣的Exception。 不要一個Exception試圖處理所有可能出現的異常。

          

這個問題多了,我敢保證幾乎所有的人都這麼使用過。這裡涉及了兩個問題,一是,捕獲了異常不做處理,二是異常訊息不夠明確。       4.1、捕獲異常不做處理,就是我們所謂的丟棄異常。我們都知道異常意味著程式出現了不可預期的問題,程式它希望我們能夠做出處理來拯救它,但是你呢?一句ex.printStackTrace()搞定,這是多麼的不負責任對程式的異常情況不理不顧。雖然這樣在調試可能會有一定的幫助,但是調試階段結束後呢?不是一句ex.printStackTrace()就可以搞定所有的事情的!

      那麼要怎麼改良呢?有四種選擇:

      1、處理異常。對所發生的異常進行一番處理,如修正錯誤、提醒。再次申明ex.printStackTrace()不算已經「處理好了異常」。

2、重新抛出异常。既然你认为你没有能力处理该异常,那么你就尽情向上抛吧!!!

3、封装异常。这是LZ认为最好的处理方法,对异常信息进行分类,然后进行封装处理。

4、不要捕获异常。

4.2、异常信息不明确。我想对于这样的:java.io.FileNotFoundException: ………信息除了我们IT人没有几个人看得懂和想看吧!所以在出现异常后,我们最好能够提供一些文字信息,例如当前正在执行的类、方法和其他状态信息,包括以一种更适合阅读的方式整理和组织printStackTrace提供的信息。起码我公司是需要将异常信息所在的类、方法、何种异常都需要记录在日志文件中的。

所以:

结论四:既然捕获了异常,就要对它进行适当的处理。不要捕获异常之后又把它丢弃,不予理睬。 不要做一个不负责的人。

结论五:在异常处理模块中提供适量的错误原因信息,组织错误信息使其易于理解和阅读。

对于异常还有以下几个注意地方:

六、不要在finally块中处理返回值。

七、不要在构造函数中抛出异常。



八、try…catch、throw、throws

在这里主要是区分throw和throws。

throws是方法抛出异常。在方法声明中,如果添加了throws子句,表示该方法即将抛出异常,异常的处理交由它的调用者,至于调用者任何处理则不是它的责任范围内的了。所以如果一个方法会有异常发生时,但是又不想处理或者没有能力处理,就使用throws吧!

而throw是语句抛出异常。它不可以单独使用,要么与try…catch配套使用,要么与throws配套使用。

//使用throws抛出异常
    public void f() throws MyException{
         try {
            FileReader reader = new FileReader("G:\\myfile\\struts.txt");  
             Scanner in = new Scanner(reader);  
             System.out.println(in.next());
        } catch (FileNotFoundException e) {
            throw new MyException("文件没有找到", e);    //throw
        }  
        
    }
登入後複製




       九、總結

   例如://m.sbmmt.com/。這篇文章對於是否需要使用異常進行了比較深刻的討論。 LZ實乃菜鳥一枚,無法理解異常深奧之處。但有一點LZ可以肯定,那就是異常必定會影響系統的效能。

      異常使用指引(摘自:Think in java)異常。

      1、在適當的層級處理問題(知道該如何處理異常的情況下才捕捉異常)。

      2、解決問題並且重新調用產生異常的方法。

      3、進行少許修補,然後繞過異常發生的地方繼續執行。

      4、以別的資料計算,以取代方法預計會回傳的數值。

      5、盡量在目前運作環境下完成的事情。然後把相同(不同)的異常重新拋到更高層。

      6、終止程序。

      7、簡單化。

      8、讓類別庫和程式更安全。 (這既是在為調試做短期投資,也是在為程序的健壯做長期投資)

異常(二)的內容,更多相關內容請關注PHP中文網(m.sbmmt.com)!


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板