FXCopを使用していくつかのレガシーコードを分析しているときに、tryブロック内で一般的な例外エラーをキャッチするのは本当に悪いことであるか、特定の例外を探している必要があります。はがきに思いを馳せてください。
15 に答える
明らかに、これは唯一の本当の答えが「それは依存する」であるそれらの質問の1つです。
それが依存する主なものは、あなたが例外をキャッチしている場所です。一般に、ライブラリは例外をキャッチすることでより保守的である必要がありますが、プログラムのトップレベル(たとえば、メインメソッドまたはコントローラーのアクションメソッドのトップなど)では、キャッチするものに対してより寛大になる可能性があります。
これは、たとえば、ライブラリに関係のない問題をマスクする可能性があるため、ライブラリ内のすべての例外をキャッチしたくないためです。たとえば、「OutOfMemoryException」のように、ユーザーが一方、main()メソッド内で例外をキャッチすることについて話している場合は、例外をキャッチして表示してから終了します...まあ、ここでほぼすべての例外をキャッチするのはおそらく安全です。
すべての例外をキャッチするための最も重要なルールは、すべての例外を黙って飲み込んではいけないということです...たとえば、Javaでは次のようになります。
try {
something();
} catch (Exception ex) {}
またはPythonでこれ:
try:
something()
except:
pass
これらは追跡するのが最も難しい問題のいくつかである可能性があるためです。
経験則として、適切に対処できる例外のみをキャッチする必要があります。例外を完全に処理できない場合は、処理できる人に例外をバブルさせる必要があります。
アプリケーションのフロントエンドでロギングとクリーンアップコードを実行していない限り、すべての例外をキャッチするのは悪いことだと思います。
私の基本的な経験則は、予想されるすべての例外をキャッチすることであり、それ以外はバグです。
すべてをキャッチして続行すると、車のダッシュボードの警告灯の上に絆創膏を置くようなものです。あなたはもうそれを見ることができませんが、それはすべてが大丈夫だという意味ではありません。
はい!(アプリケーションの「上部」を除く)
例外をキャッチしてコードの実行を続行できるようにすることで、特定の問題に対処して回避する方法、または特定の問題を修正する方法を知っていることを示しています。あなたはこれが回復可能な状況であると述べています。例外またはSystemExceptionをキャッチすると、IOエラー、ネットワークエラー、メモリ不足エラー、コードの欠落エラー、nullポインタの間接参照などの問題をキャッチできます。あなたがこれらに対処できると言うのは嘘です。
適切に編成されたアプリケーションでは、これらの回復不能な問題はスタックの上位で処理する必要があります。
さらに、コードが進化するにつれて、呼び出されたメソッドに将来追加される新しい例外を関数がキャッチすることを望まないでしょう。
私の意見では、予想されるすべての例外をキャッチする必要がありますが、このルールはインターフェイス ロジック以外に適用されます。コール スタック全体で、おそらくすべての例外をキャッチし、ログを記録し、ユーザー フィードバックを提供し、必要に応じて可能な場合は正常にシャットダウンする方法を作成する必要があります。
ユーザーフレンドリーでないスタックトレースが画面にダンプされてアプリケーションがクラッシュすることほど悪いことはありません。これは、コードに対する (おそらく望ましくない) 洞察を与えるだけでなく、エンド ユーザーを混乱させ、競合するアプリケーションに怖がらせてしまうことさえあります。
この問題については、多くの哲学的議論 (議論のようなもの) がありました。個人的には、最悪のことは例外を飲み込むことだと思います。次の最悪の事態は、ユーザーが技術的な巨大なジャンボでいっぱいの厄介な画面を取得する表面に例外が発生することを許可することです。
ええと、一般的な例外をキャッチすることと特定の例外をキャッチすることの間に違いはありません。ただし、複数のキャッチブロックがある場合は、例外が何であるかによって異なる反応を示す可能性があります。
結論として、あなたはとジェネリックの両方IOException
を捕まえるでしょう、しかしあなたのプログラムが反応するべき方法はおそらく異なっています。NullPointerException
Exception
ポイントは2つあると思います。
まず、どのような例外が発生したかわからない場合、どのようにしてそれから回復することを期待できますか。ユーザーがファイル名を間違って入力する可能性があると予想される場合は、FileNotFoundExceptionを予期して、ユーザーに再試行するように指示できます。同じコードがNullReferenceExceptionを生成し、ユーザーに再試行するように指示しただけでは、何が起こったのかわかりません。
次に、FxCopガイドラインはライブラリ/フレームワークコードに焦点を当てています。すべてのルールがEXEまたはASP.NetWebサイトに適用できるように設計されているわけではありません。したがって、すべての例外をログに記録してアプリケーションを適切に終了するグローバル例外ハンドラーを用意することは良いことです。
すべての例外をキャッチすることの問題は、予期しないもの、または実際にキャッチすべきではないものをキャッチしている可能性があることです。実際には、あらゆる種類の例外は何かがうまくいかなかったことを示しており、続行する前にそれを整理する必要があります。そうしないと、データの整合性の問題や、追跡が容易ではないその他のバグが発生する可能性があります。
一例を挙げると、あるプロジェクトで CriticalException という例外タイプを実装しました。これは、開発者や管理スタッフによる介入が必要なエラー状態を示しています。そうしないと、顧客に誤った請求が行われたり、その他のデータ整合性の問題が発生したりする可能性があります。また、例外をログに記録するだけでは不十分で、電子メール アラートを送信する必要がある場合にも使用できます。
例外の概念を正しく理解していない別の開発者は、この例外をスローする可能性のあるコードを、すべての例外を破棄する一般的な try...catch ブロックにラップしました。幸いなことに、私はそれを見つけましたが、深刻な問題を引き起こす可能性がありました。特に、キャッチするはずだった「非常にまれな」コーナーケースが、予想よりもはるかに一般的であることが判明したためです。
したがって、どのような種類の例外がどのような状況でスローされるかを 100% 確実に把握していない限り、一般的に、一般的な例外をキャッチすることは良くありません。疑わしい場合は、代わりに最上位の例外ハンドラーにバブルアップさせてください。
ここでの同様のルールは、System.Exception 型の例外を決してスローしないことです。あなた (または別の開発者) は、特定の例外をコール スタックの上位でキャッチし、他の人を通過させたい場合があります。
(ただし、注意すべき点が 1 つあります。.NET 2.0 では、スレッドがキャッチされていない例外に遭遇すると、アプリ ドメイン全体がアンロードされます。そのため、スレッドの本体を一般的な try...catch ブロックでラップして渡す必要があります。そこでキャッチされたすべての例外は、グローバル例外処理コードに渡されます)。
まったく異なる 2 つの使用例があります。1 つ目は、ほとんどの人が考えているもので、チェック例外を必要とする操作に try/catch を配置します。これは決してキャッチオールであってはなりません。
ただし、2 つ目は、プログラムが続行できるときに、プログラムが壊れないようにすることです。これらのケースは次のとおりです。
- すべてのスレッドの先頭 (デフォルトでは、例外は跡形もなく消えます!)
- 終了しないと予想されるメイン処理ループ内
- オブジェクトのリストを処理するループ内で、1 つの障害が他の障害を停止してはならない
- 「メイン」スレッドのトップ -- メモリが不足したときに少量のデータを stdout にダンプするなど、ここでクラッシュを制御できます。
- コードを実行する「ランナー」がある場合 (たとえば、誰かがリスナーを追加してリスナーを呼び出した場合)、コードを実行するときに例外をキャッチして問題をログに記録し、他のリスナーに引き続き通知できるようにする必要があります。
これらのケースでは、プログラミング/予期しないエラーをキャッチし、ログに記録して続行するために、常に例外 (場合によってはスロー可能) をキャッチする必要があります。
フレームワーク内から特定の例外のみをキャッチするのが良いガイドラインだと思います(ホストアプリケーションがディスクのいっぱいになるなどのエッジケースを処理できるようにするため)が、すべてをキャッチできない理由がわかりませんアプリケーションコードからの例外。非常に簡単に言えば、何がうまくいかなくても、アプリをクラッシュさせたくない場合があります。
ほとんどの場合、一般的な例外をキャッチする必要はありません。もちろん選択の余地がない場合もありますが、その場合はなぜ捕まえる必要があるのかを確認したほうがいいと思います。たぶんあなたのデザインに何か問題があります。
一般的な例外をキャッチすると、燃えている建物の中でダイナマイトの棒を持ち、信管を消すような気がします。しばらくは役に立ちますが、しばらくするとダイナマイトが爆発します。
もちろん、一般的な例外をキャッチする必要がある状況もありますが、それはデバッグ目的のためだけです。エラーやバグは隠すのではなく、修正する必要があります。