例外が強力なデバッグ方法である理由は、次の3つの質問に答えるためです。
1。何が問題になったのですか?
2。どこで間違いを犯しましたか?
3.なぜ何かがうまくいかなかったのですか?
例外の効果的な使用の場合、例外タイプは「何がスローされますか」と答え、例外スタックトレースは「」と回答します。
デバッグ中に良い例外の使用を最大化するのに役立つ3つの原則があります。これらの3つの原則は次のとおりです。
1。具体的で明確
2。早めに投げます
3.キャプチャを遅延します
効果的な例外処理のこれら3つの原則を説明するために、この記事では、預金や引き出しや請求請求などの銀行口座の活動を記録および追跡するために使用される個人財務マネージャーJCheckbookを製造することで説明します。
具体的で透明
Javaは、例外クラスの階層を定義します。これは、スロー可能なスロー可能で始まり、エラーと例外が拡張され、例外がruntimeexceptionを拡張します。図1に示すように。
これらの4つのクラスは一般化されており、多くのエラー情報を提供しません。これらのクラスをインスタンス化することは構文的に合法ですが(new Throwable()など)、仮想ベースクラスとして扱い、より専門的なサブクラスを使用するのが最善です。 Javaは、多数の例外サブクラスを提供しています。より具体的にしたい場合は、独自の例外クラスを定義することもできます。
たとえば、java.ioパッケージは、FilenotFoundexception、eofexception、ObjectStreamexceptionなどのIOExceptionのより専門的でサブクラスである例外クラスioExceptionのサブクラスを定義します。それぞれは、I/Oエラーの特定のクラスについて説明します:ファイルの損失、例外ファイルの終了、およびエラーシリアル化オブジェクトストリーム。例外が具体的になればなるほど、私たちのプログラムは「何がうまくいかなかったのか」という質問に答えることができます。
また、例外をキャッチする際には、できるだけ明確にするようにすることも重要です。たとえば、JCheckbookは、ユーザーのファイル名を再クエリすることにより、FilenotFoundExceptionを処理できます。 eofexceptionの場合、例外がスローされる前に読み取られた情報に基づいて実行され続けることができます。 ObjectStreamExceptionがスローされている場合、プログラムはファイルが破損していることをユーザーに促し、バックアップファイルまたは他のファイルを使用する必要があります。
Javaは、同じTryブロックの複数のキャッチブロックを定義できるため、各例外を適切に扱うことができるため、明示的に例外を簡単にキャッチすることができます。
ファイルprefsfile = new file(prefsfilename); try {readpreferences(prefsfile);} catch(filenotfoundexception e){//指定されたファイル//が存在しないことをユーザーに警告} catch(//ファイルの終わり//に到達したことをユーザーに警告} ception(ObjectStreamexception e){//ユーザーは、ユーザーがcatched the catched the catched the is eart the eart the eart the eart the eart the eart the eart the catched ex ex ex exex他のI/O //エラーが発生したこと}JCheckbookは、複数のキャッチブロックを使用して、例外のキャプチャに関する明示的な情報をユーザーに提供します。たとえば、FilenotFoundExceptionがキャッチされている場合、ユーザーに別のファイルを指定するように促すことができます。場合によっては、複数のキャッチブロックによってもたらされる追加のエンコーディングの取り組みは、必須ではない負担である可能性がありますが、この例では、追加のコードはプログラムがよりユーザーフレンドリーな応答を提供するのに役立ちます。
最初の3つのキャッチブロックによって処理された例外に加えて、最後のキャッチブロックは、IOExceptionがスローされたときに、より一般化されたエラー情報をユーザーに提供します。これにより、プログラムは可能な限り特定の情報を提供できますが、他の予期しない例外を処理する機能もあります。
開発者は正規化された例外をキャッチし、例外クラス名または「特異性」のスタック情報を印刷することがあります。これをしないでください!ユーザーは、 java.io.EOFExceptionまたはStack情報を見ると、ヘルプを得るのではなく、頭痛がします。特定の例外をキャプチャする必要があり、ユーザーは「人間の言葉」で促される必要があります。ただし、例外スタックはログファイルに印刷できます。例外とスタック情報は、ユーザーではなく開発者を支援するために使用されることを忘れないでください。
最後に、JCheckbookはreadPreferences()で例外をキャッチしないが、ユーザーインターフェイスレイヤーにキャッチと処理の例外を残して、ユーザーにダイアログボックスまたはその他のメソッドを使用して通知できるようにすることに注意する必要があります。これは「遅延キャプチャ」と呼ばれ、以下で説明します。
早く捨ててください
例外スタック情報は、例外が発生するシーンを正確に見つけるために、クラス名、メソッド名、コードファイル名、および各メソッドコールの行番号を含む、例外を発生させるメソッドコールチェーンの正確な順序を提供します。
java.lang.nullpointerexceptionat java.io.fileinputStream.open(ネイティブ方法)java.io.fileinputStream jcheckbook.jcheckbook.startup(jcheckbook.java:116)at jcheckbook.jcheckbook。
上記は、FileInputStreamクラスのOpen()メソッドがNullPointerExceptionをスローする場合を示しています。ただし、 FileInputStream.close()は標準のJavaクラスライブラリの一部であり、この例外の問題は、コード自体がJava APIではないことである可能性が高いことに注意してください。そのため、問題は以前の方法の1つに表示される可能性が高く、幸いなことに、スタック情報にも印刷されています。
残念ながら、nullpointerexceptionは、Javaで最も有益ではない(最も一般的でクラッシュする)例外です。私たちが最も気にかけていることはまったく言及していません。それで、私たちは数歩戻って、何かがうまくいかなかった場所を見つけなければなりませんでした。
追跡スタック情報をバックしてコードをチェックすることにより、エラーの原因は、空のファイル名パラメーターがreadPreferences()に渡されたことであると判断できます。 readPreferences()は空のファイル名を処理できないことを知っているので、すぐに状態を確認してください。
public void readpreferences(string filename)は、Illegalargumentexceptionをスローします{if(filename == null){throw new IllegalargumentException( "filename is null"); } // if //...他の操作を実行する... inputstream in = new fileinputStream(filename); //...設定ファイルを読み取る...}例外を早期にスローすることで(「迅速に失敗」とも呼ばれます)、例外は明確で正確です。スタック情報は、すぐに問題が発生したもの(違法なパラメーター値が提供された)、それがうまくいかなかった理由(ファイル名がnullにならない)、そしてそれがどこで間違ったか( readPreferences()の最初の部分)を反映しています。このようにして、私たちのスタック情報は正直に提供することができます:
java.lang.illegalargumentexception:filenameはnullat jcheckbook.jcheckbook.java:207)のjcheckbook.startup(jcheckbook.java:116)at jcheckbook.jcheckbook。 jcheckbook.jcheckbook.main(jcheckbook.java:318)
さらに、ITに含まれる例外情報(「ファイル名は空」)により、前のコードでは空の質問に明示的に回答することにより、例外が豊富になります。
エラーが検出されるとすぐに例外をスローすることで障害が達成され、ファイルやネットワーク接続などの不必要なオブジェクトの構築またはリソースの使用は効果的に回避できます。同様に、これらのリソースを開くことによってもたらされたクリーニング操作は保存できます。
キャプチャの遅延
初心者とマスターの両方が行うことができる間違いの1つは、例外を処理する能力を持つ前にプログラムをキャッチすることです。 Javaコンパイラは、チェックされた例外をキャッチまたはスローする必要があることを要求することにより、この動作を間接的に促進します。自然な方法は、すぐにトライブロックでコードをラップし、CATCHを使用して例外をキャッチして、コンパイラのエラーを回避することです。
問題は、捕まった後に例外を取得した場合はどうすればよいですか?最悪のことは何もすることです。空のキャッチブロックは、例外全体をブラックホールに投入することと同等であり、エラーがいつ、どこで間違っているのかを説明できるすべての情報が永遠に失われます。ログに例外を記述する方が少し良いです。少なくとも確認するレコードがあります。ただし、ユーザーがログファイルや例外情報を読み取ったり理解したりすることを期待することはできません。また、JCheckbookは現在デスクトップアプリケーションであるが、HTMLベースのWebアプリケーションに変えることも計画しているため、 readPreferences() [エラーメッセージ]ダイアログを表示することも適切ではありません。その場合、エラーダイアログを表示することは明らかにオプションではありません。同時に、HTMLまたはC/Sバージョンに関係なく、構成情報がサーバー上で読み取られ、エラーメッセージをWebブラウザーまたはクライアントプログラムに表示する必要があります。また、 readPreferences()は、設計時にこれらの将来のニーズを考慮する必要があります。ユーザーインターフェイスコードとプログラムロジックの適切な分離は、コードの再利用性を改善できます。
条件付き処理の前に例外を時期尚早にキャッチすると、より深刻なエラーやその他の例外が発生することがよくあります。たとえば、上記のreadPreferences()メソッドがすぐにキャプチャして記録した場合、FileInputStreamコンストラクターが呼び出されたときにスローされる可能性のあるFilenotFoundExceptionを記録すると、コードは次のようになります。
public void readpreferences(string filename){// ... inputstream in = null; //これを行わないでください!!! try {in = new fileInputStream(filename);} catch(filenotfoundexception e){logger.log(e);} in.read(...); // ...}上記のコードは、filenotfoundexceptionから回復する能力なしでそれをキャプチャします。ファイルが見つからない場合、次の方法では明らかに読み取ることができません。 readpreferences()が存在しないファイルを読み取るように求められた場合はどうなりますか?もちろん、FilenotFoundExceptionが記録され、その時点でログファイルを見れば、私たちは知っています。ただし、プログラムがファイルからデータを読み取ろうとするとどうなりますか?ファイルは存在しないため、変数は空で、nullpointerexceptionがスローされます。
プログラムをデバッグするとき、本能は、ログの最後にある情報を見るように指示します。それはnullpointerexceptionであり、非常に厄介なのは、この例外が非常に非特異的であることです。エラーメッセージは、何がうまくいかなかったか(実際のエラーはnullpointerexceptionの代わりにfilenotfoundexceptionです)を誤解させるだけでなく、エラーのソースも誤解を招きます。本当の問題は、スローされたnullpointerexceptionの行数の外側であり、いくつかのメソッド呼び出しとクラスの破壊があるかもしれません。私たちの注意は、ログを振り返って問題の原因を見つけるまで、小さな魚による本当の間違いから引き出されました。
readPreferences()本当にすべきことは、これらの例外をキャッチしないことであるため、それはどうあるべきですか?それは少し直感に反しているようで、最も適切な方法は何もしないことであり、すぐに例外をキャッチしないことです。 readPreferences()の発信者に責任を任せ、不足している構成ファイルに対処するための適切な方法を研究させます。ユーザーに他のファイルを指定するか、デフォルト値を使用するように促す場合があります。実際に機能しない場合は、ユーザーに警告し、プログラムを終了する場合があります。
コールチェーンの上流の例外の責任を渡す方法は、メソッドのスロー条項で例外を宣言することです。可能な例外を宣言する場合は、注意してください。具体的にはより良いです。これは、メソッドを呼び出すプログラムが知り、処理する準備をする必要がある例外のタイプを識別するために使用されます。たとえば、 readPreferences()の「遅延キャプチャ」バージョンは次のようになる場合があります。
public void readpreferences(string filename)は、Illegalargumentexception、filenotfoundexception、ioexception {if(filename == null){show new elegalargumentexception( "filename is null"); } // if // ... inputstream in = new fileinputStream(filename); // ...}技術的には、宣言する必要がある唯一の例外はIOExceptionですが、このメソッドがFilenotFoundExceptionをスローする可能性があることを明示的に宣言します。 IllegalArgumentExceptionは、非チェックの例外であるため、宣言する必要はありません(つまり、Runtimeexceptionのサブクラス)。ただし、コードを文書化するために宣言されています(これらの例外は、メソッドのJavadocsでもマークする必要があります)。
もちろん、最終的にはプログラムが例外をキャッチする必要があります。そうしないと、予期せず終了します。しかし、ここでの秘trickは、プログラムが例外から有意義に回復し、より深いエラーを引き起こすことなく継続できるように、適切なレベルで例外をキャッチすることです。または、ユーザーにエラーから回復するようにガイドするなど、ユーザーに明確な情報を提供することができます。メソッドが有能でない場合は、例外を処理しないでください。適切なレベルでキャッチして処理するために残してください。
要約します
経験豊富な開発者は、プログラムのデバッグの最大の困難は、欠陥を修正することではなく、膨大な量のコードから欠陥の隠れ場所を見つけることであることを知っています。この記事の3つの原則に従う限り、あなたの例外は、欠陥を追跡して排除するのに役立ち、プログラムをより堅牢でユーザーフレンドリーにします。上記はこの記事の全体的な内容であり、それがあなたの研究や仕事に役立つことを願っています。