ホームページ >Java >&#&チュートリアル >Java の改善 (17)-----例外 (2)

Java の改善 (17)-----例外 (2)

黄舟
黄舟オリジナル
2017-02-10 11:45:301063ブラウズ

前回のブログ投稿からの続き: Java 改善章 (16) -----例外 (1)

5. カスタム例外

Java は多くの例外を提供しますが、例外システムは報告したいすべてのエラーを予測することはできません。そのため、Java では例外をカスタマイズして、プログラム内で発生する可能性のある特定の問題を表現できます。 、一言で言えば、Java の既存の例外タイプに固執する必要はありません。

Java カスタム例外を使用するには、次の 4 つの手順が必要です。

1. 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 例外メカニズムも例外チェーンというチェーンを提供します。

例外メッセージに遭遇するたびに、...キャッチを試みる必要があることはわかっています。1 つだけで問題ありませんが、複数の例外がある場合はどうなるでしょうか?分類処理は確実に面倒になるので、すべての例外を解決するには 1 つの例外を使用します。これは確かに可能ですが、このアプローチでは必然的にその後のメンテナンスがより困難になります。最善の方法は、これらの例外情報をカプセル化してから、カプセル化クラスをキャプチャすることです。

確かに、アプリケーションでは、例外をカプセル化するだけでなく、例外を渡す必要がある場合もあります。配達方法は?投げる!過食症、正解です! !しかし、例外をスローするために throw のみを使用する場合、カプセル化されたクラスをどうすればよいでしょうか? ?異常時の対処法としては、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

ここで何を見つけましたか?例外は実行プロセスを変更します。 !良い点は、例外によってプログラムの実行フローが変更されることです。プログラム内で例外が発生した場合、 out.close(); は実行されず、必然的にリソースが解放されなくなります。したがって、プログラムがファイル、ソケット、JDBC 接続などのリソースを使用する場合、例外が発生した場合でも、占有されているリソースが正しく解放されることを確認する必要があります。ここで、finally が登場します。例外が発生するかどうかに関係なく、finally は常に実行する機会があるため、リソースを解放するのに最適です。

結論 2: すべてのリソースが正しく解放されていることを確認します。 finally キーワードを最大限に活用してください。

このコードの場合、ほとんどの人はこのように処理されると思います (LZ も同様です) 。このようなコードを使用する人は、1 つのキャッチですべての例外を解決できるという考え方を持っています。これは可能ですが、お勧めできません。なぜ!まず、catch ブロックはどのような例外が発生すると予想され、どのような処理を行う必要があるかを理解する必要があります。Exception を使用するということは、すべての例外情報を処理する必要がありますが、それを行うことにどのような意味があるのか​​を理解する必要があります。それで?

ここで、上記のプログラム例をもう一度見てみましょう。明らかに、SQLException と IOException という 2 つの例外メッセージをスローする必要があるかもしれません。したがって、1 つのキャッチが 2 つの完全に異なる例外を処理することは明らかに不適切です。 2 つのキャッチを使用し、1 つは SQLException の処理に、もう 1 つは IOException の処理に使用した方がはるかに優れています。つまり:

結論 3: catch ステートメントは、範囲が広すぎる例外クラスを指定するのではなく、特定の例外タイプを指定するように努めるべきです。 考えられるすべての例外を 1 つの例外で処理しようとしないでください。 これには多くの問題がありますが、ほぼ全員がそれを使用していることは保証できます。ここには 2 つの問題が関係しています。1 つは例外がキャッチされるが処理されないこと、もう 1 つは例外情報が十分に明確ではないことです。 4.1. 例外を処理せずにキャッチすることを、例外の破棄と呼びます。例外がプログラム内で予期せぬ問題が発生したことを意味することは誰もが知っていますが、プログラムはそれを処理して保存できることを望んでいます。 ex.printStackTrace() の 1 文だけで十分です。プログラムの異常な状況を無視するのは、なんと無責任なことでしょう。これはデバッグ中には役立つかもしれませんが、デバッグ段階が終了した後はどうなるでしょうか? ex.printStackTrace() だけですべてを実行できるわけではありません。

では、どうすれば改善できるのでしょうか?オプションは 4 つあります:

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




9. まとめ

実際、例外使用の利点と欠点については確かに多くの議論があります。例: http://www.php.cn/。このブログ投稿では、例外を使用するかどうかについてさらに詳しく説明しています。 LZは本当に新人なので、あまりにも奥深いことは理解できません。しかし、LZ が確信できることの 1 つは、異常がシステムのパフォーマンスに確実に影響を与えるということです。

例外の使用ガイド (Java で考える) から抜粋

以下の状況では例外を使用する必要があります。 1. 問題を適切なレベルで処理します (例外を処理する方法を知っている場合にのみ例外をキャッチします)。

2. 問題を解決し、例外を生成したメソッドを再度呼び出します。

3. 小さなパッチを作成し、例外が発生した場所をバイパスして実行を続行します。 4. 他のデータを使用して計算を実行し、メソッドによって返されると予想される値を置き換えます。运当前5、現在の動作環境でできることをできるだけやってください。次に、同じ (異なる) 例外がより高いレベルに再スローされます。

6. プログラムを終了します。

7. 簡素化します。

8. クラスライブラリとプログラムをより安全にします。 (これは、デバッグのための短期的な投資でもあり、プログラムの堅牢性のための長期的な投資でもあります)

上記は Java 改善の章 (17) です。 ----- 例外 (2) のコンテンツについては、PHP 中国語 Web サイト (www.php.cn) に注目して、関連コンテンツをご覧ください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。