web-dev-qa-db-ja.com

「プログラミングエラー」の例外-アプローチは適切ですか?

私は現在、例外の使用を改善しようとしていますが、プログラミングエラーを示す例外(たとえば、誰かが引数としてnullを渡した、またはオブジェクトが破棄された後にメソッドを呼び出した)と、呼び出し側の障害ではない操作(I/O例外など)。

これらの2種類の例外はどのように異なる方法で処理する必要がありますか?エラー例外を明示的に文書化する必要があると思いますか、または関連する前提条件を文書化するだけで十分ですか?また、前提条件またはエラー例外の説明が明らかである必要がある場合は、ドキュメントを省略できますか(たとえば、破棄されたオブジェクトでメソッドを呼び出す場合はObjectDisposedException

9
Medo42

私はあなたが正しい軌道に乗っていると思います。スローされる可能性があるすべての例外をスロー、キャッチ、または文書化することは、あまり意味がありません。製品の厳格性により、より高度な例外的な雇用と文書化が必要になる場合があります(システムの特定の安全上重要な側面など)。

契約の概念を使用して、特にダウンストリームの呼び出し元(パブリックメンバーや保護されたメンバーに似ているものなど)の前提条件(および事後条件)を特定する、より防御的な戦略は、多くの場合、より効果的でより柔軟になります。これは実装だけでなくドキュメントにも当てはまります。開発者が何が期待されているかを知っていれば、ルールに従う可能性が高くなり、作成したコードが混乱したり誤用されたりする可能性が低くなります。

文書化する必要がある一般的なものの一部には、nullパラメーターのケースが含まれます。多くの場合、それらを使用すると、通常は予期されない結果が得られますが、さまざまな理由で許可されて使用されるため、場合によっては柔軟性が高くなります。 null、またはその他の特別な非有理値(負の時間、負の数量など)を許可するパラメーターを持つメンバーのコンシューマーとして、それらが識別され、説明されることを期待しています。

Null以外のパラメーターの場合、パブリックまたは保護されたメンバーのコンシューマーとして、nullは許可されないことを知りたいです。特定のコンテキストで有効な値の範囲を知りたい。通常の範囲外の値を使用した場合の結果を知りたいが、それ以外の場合は別の呼び出しコンテキストで有効です(たとえば、型の値は通常、どの操作でも有効ですが、ここでは無効です-ブール値パラメーターのように有効な値としてfalseを期待しないでください。

プラットフォーム、またはその他のよく知られているインターフェースに関しては、ドキュメント化するために極端に行く必要はないと思います。ただし、開発者として、プラットフォームのガイダンスと実装を変える機会があるので、ガイダンスが有益である可能性があることをどのように追跡するかに注意してください。

IDisposableに固有であり、多くの場合、このインターフェイスの実装は、明示的な破棄プロセスよりも優先される代替方法を提供します。これらの場合は、推奨される方法を強調し、明示的な廃棄は推奨されないことに注意してください。

2
JustinC

ここに私自身の考えがあります。これが最善の方法であると確信しているわけではないことに注意してください。そのため、最初にこの質問を作成しました。

私が理解している限り、呼び出し元がプログラミングエラーの例外を実際に処理することはほとんど意味がありません。代わりに、前提条件が満たされていることを確認する必要があります。タスクの境界にある「外側の」例外ハンドラーのみがそれらをキャッチする必要があるため、タスクが失敗した場合でもシステムを実行し続けることができます。

クライアントコードがエラー例外を誤ってキャッチすることなく「失敗」例外を確実にキャッチできるようにするために、すべての失敗例外に対して独自の例外クラスを作成し、それらをスローするメソッドにドキュメント化します。 Javaで例外をチェックするようにします。

最近まで、メソッドがスローする可能性のあるすべての例外を文書化しようとしましたが、エラーが発生しないことがわかるまで、呼び出しチェーンのすべてのメソッドで文書化する必要がある不当なリストが作成される場合があります。代わりに、要約/パラメーターの説明に前提条件を文書化し、満たされていない場合に何が起こるかについては触れません。とにかく、人々はこれらの例外を明示的にキャッチしようとすべきではないので、それらのタイプを文書化する必要はありません。

前提条件を文書化するために、明白なことを言うと不必要な混乱が生じるだけです。nullをメソッドに渡しても意味がない場合、たとえそれが文書化されていなくても、呼び出し側はnullを渡すと例外を予期する必要があります。 ObjectDisposedExceptionの場合も同じです。このインターフェイスは非常に広く使用されているため、Disposeを呼び出す人は、誰もオブジェクトを使い続けないようにする責任を認識しています。

2
Medo42

合理的な経験則:

  1. 修正できる例外をすべてキャッチします。
  2. 修正できない例外についても、キャッチしてコメントし、再スローしてください。
  3. デフォルトの処理よりも適切に処理または診断できない例外をキャッチしないでください。

トップレベルの致命的ではない例外ハンドラーを使用して、以下で処理できなかったものをトラップして、アプリケーションのフォールオーバーを防止しようとする場合がありますが、これは特定のアプリケーションに強く依存します。たとえば、iOSアプリケーションは可能な限りトラップすることを好みます。コマンドラインアプリは、ほとんど例外をまったくトラップしない場合、完全に問題ない可能性があります。

1
Joe McMahon

Javaはすべての例外を「文書化」するわけではありません。throw句ですべてのthrowsn例外を記述する必要があるにもかかわらず、コードのどの行でもスローできますRuntimeExceptionメソッドシグネチャで宣言する必要はありません。

0
Ross Patterson

これを行う標準的な方法は、Javaアプローチを使用することです。プログラミングエラーは、チェックされていない例外であり、高速な障害を確実にするためにキャッチされるべきではありません。契約エラーはチェックされた例外であり、クライアント。

0
J.Ashworth