web-dev-qa-db-ja.com

例外の伝播:いつ例外をキャッチする必要がありますか?

MethodAがMethodBを呼び出し、次にMethodBがMethodCを呼び出します。

MethodBまたはMethodCには例外処理はありません。ただし、MethodAには例外処理があります。

MethodCでは例外が発生します。

さて、その例外は適切に処理するMethodAにまで至っています。

これの何が問題になっていますか?

私の心の中で、ある時点で、呼び出し元がMethodBまたはMethodCを実行し、それらのメソッドで例外が発生した場合、それらのメソッド内で例外を処理することから何が得られますか?彼らは呼び出された人に泡立ちますか?

例外処理に関するステートメントまたはコンセンサスは、それだけでは実行を続行できない場合に例外をスローすることです。わかった。しかし、try/catchブロックをずっと下に置くのではなく、チェーンのさらに上のところで例外をキャッチしないのはなぜですか。

リソースを解放する必要があるときに理解します。それはまったく別の問題です。

46
Daniel Frost

一般的な原則として、例外の処理方法を理解していない限り、例外をキャッチしないでください。 MethodCが例外をスローしたが、MethodBがそれを処理するための有用な方法を持っていない場合は、例外をMethodAまで伝播させる必要があります。

メソッドにキャッチアンドスローメカニズムが必要な唯一の理由は次のとおりです。

  • 1つの例外を、上記の呼び出し元にとってより意味のある別の例外に変換したい。
  • 例外に情報を追加したい。
  • リソースなしでリークされるリソースをクリーンアップするには、catch句が必要です。

それ以外の場合、誤ったレベルで例外をキャッチすると、呼び出し側のコード(および最終的にはソフトウェアのユーザー)に有用なフィードバックを提供せずに、黙って失敗するコードが生成される傾向があります。例外をキャッチしてすぐに再スローするという選択肢は無意味です。

140
Simon B

これの何が問題になっていますか?

何もない。

さて、その例外は適切に処理するMethodAにまで至っています。

「適切に処理する」ことが重要な部分です。それが構造化例外処理の要です。

あなたのコードが例外で「有用な」何かをすることができるなら、それのために行きます。そうでない場合は、まあまあ。

。 。 。 try/catchブロックをずっと下に置くのではなく、チェーンのさらに上のところに例外をキャッチしないのはなぜですか。

それがまさにあなたがしていることすべきです。ハンドラ/リスローアが「ずっと下に」あるコードを読んでいる場合は、[おそらく]かなり貧弱なコードを読んでいることになります。

悲しいことに、一部の開発者は、catchブロックを、作成したすべてのメソッドにスローする(意地悪ではない)「ボイラープレート」コードと見なしています。例外は「エスケープ」せず、プログラムを強制終了しません。

ここでの難しさの一部は、mostのとき、例外が常にスローされるわけではないので、この問題に気付かないこともありますare =、プログラムは非常に多くの時間と労力を浪費し、コールスタックの選択を徐々に解除して、例外で実際に何か有用な場所に到達します。

21
Phill W.

ライブラリとアプリケーションを区別する必要があります。

ライブラリはキャッチされていない例外を自由にスローできます

ライブラリを設計するとき、どこかで問題が発生する可能性について考える必要があります。パラメータが誤った範囲またはnullにある、外部リソースが利用できないなどの可能性があります。

ほとんどの場合、ライブラリには賢明な方法でそれらを処理する方法がありません。唯一の賢明な解決策は、適切な例外をスローし、アプリケーションの開発者にそれを処理させることです。

アプリケーションは常にある時点で例外をキャッチする必要があります

例外がキャッチされたら、それらをErrorsまたはFatal Errorsのいずれかに分類します。通常のErrorは、アプリケーション内の1つの操作が失敗したことを意味します。たとえば、宛先が書き込み可能でないため、開いているドキュメントを保存できませんでした。アプリケーションが行うべき賢明な考えは、操作を正常に完了できなかったことをユーザーに通知し、問題に関して人間が読める情報を提供してから、ユーザーに次に何をするかを決定させることです。

致命的なエラーは、メインのアプリケーションロジックから回復できないエラーです。たとえば、ビデオゲームでグラフィックスデバイスドライバーがクラッシュした場合、アプリケーションがユーザーに「正常に」通知する方法はありません。この場合、ログファイルを書き込み、可能であれば、何らかの方法でユーザーに通知する必要があります。

このような重大な場合でも、アプリケーションはこの例外を意味のある方法で処理する必要があります。これには、ログファイルの書き込み、クラッシュレポートの送信などが含まれます。アプリケーションが何らかの理由で例外に応答しない理由はありません。

8
MechMK1

あなたが説明するパターンの何が問題になっているのかというと、メソッドAには3つのシナリオを区別する方法がないということです。

  1. 方法Bは予期された方法で失敗しました。

  2. メソッドCは、メソッドBで予期されない方法で失敗しましたが、メソッドBが安全に破棄できる操作を実行しているときに失敗しました。

  3. メソッドCはメソッドBによって予期されない方法で失敗しましたが、メソッドBが一時的な予定のインコヒーレント状態にある操作を実行している間に、BがCの失敗のためにクリーンアップに失敗しました。

メソッドAがこれらのシナリオを区別できる唯一の方法は、Bからスローされた例外にその目的に十分な情報が含まれているか、またはメソッドBのスタックのアンワインドによってオブジェクトが明示的に無効化状態。残念ながら、ほとんどの例外フレームワークは両方のパターンを扱いにくくし、プログラマーに「より悪さの少ない」設計の決定を行わせます。

0
supercat