多くの場合、関数を書くときは、そのようなエラーをできるだけ早く検出するために、入力を有効にする必要があります(これらは前提条件と呼ばれます)。前提条件が失敗すると、常に例外がスローされます。しかし、これがベストプラクティスであるかどうか、そしてそうでない場合はアサーションがより適切かどうかを疑い始めています。
それで、いつアサーションを使用するのが適切であり、いつ例外をスローするのが適切であるのか、どちらを行う必要がありますか?
多くの場合、関数を書くときは、そのようなエラーをできるだけ早く検出するために、入力を有効にする必要があります(これらは前提条件と呼ばれます)。前提条件が失敗すると、常に例外がスローされます。しかし、これがベストプラクティスであるかどうか、そしてそうでない場合はアサーションがより適切かどうかを疑い始めています。
それで、いつアサーションを使用するのが適切であり、いつ例外をスローするのが適切であるのか、どちらを行う必要がありますか?
回答:
アサーションは、論理的に偽であることが不可能であるはずの条件を検証するためにのみ使用する必要があります(正気チェックを参照)。これらの条件は、独自のコードによって生成された入力のみに基づいている必要があります。外部入力に基づくチェックでは、例外を使用する必要があります。
私が従う傾向がある簡単なルールは、プライベート関数の引数をアサートで検証し、パブリック/保護された関数の引数に例外を使用することです。
アサーションは、プログラミングエラーを見つけるために使用されます。すべてのアサーションが削除されると、プログラムも同様に機能する必要があります。
一方、例外は、プログラムが完全であっても発生する可能性がある状況です。それらは、ハードウェア、ネットワーク、ユーザーなどの外部の影響によって引き起こされます。
典型的なプログラミング方法は、実動/リリースビルドからアサーションをコンパイルすることです。アサーションは、仮定の失敗を見つけるための内部テスト中にのみ役立ちます。外部機関の振る舞いを想定しないでください。そのため、ネットワークまたはユーザーからのイベントをアサートしないでください。また、アサーションが失敗した場合にプロダクションビルドの処理コードを記述することをお勧めします。
たとえば、Cでは、
int printf(const char *fmt, ...)
{
assert(fmt); // may fail in debug build but not in production build
if (!fmt) return -1; // handle gracefully in production build
...
}
例外は、実動ビルドに組み込まれることを意図しています。例外の代替は、アサーションではなくエラーを返すことです。
私にとってアサートの問題の1つは、Javaでデフォルトで無効になっていることです。
不良データ(予期しない形式)の場合のデータ破損を避けるため、プログラム(何年も無人で実行されている可能性があります)をできるだけ早くクラッシュさせる必要があるフェイルファースト戦略を使用します。これはチェックを使用するものであり、アサートを使用することにより、基本的にそれらがアクティブにならないリスクがあります。