Java例外処理とassert
条件の使用の違いは何ですか?
Assertには2つのタイプがあることが知られています。しかし、いつassert
キーワードを使用すべきですか?
コード内の内部ロジックチェックにはアサーションを使用し、即時コードの制御外のエラー状態には通常の例外を使用します。
アサーションはオンとオフを切り替えることができることを忘れないでください-引数の検証などが気になる場合は、例外を使用して明示的に行う必要があります。 (ただし、アサーションを使用してprivateメソッドで引数検証を実行することを選択できます。これは、その時点での違反が外部エラーではなく内部バグによるものであるという理由によります。)
あるいは、すべてに例外を使用することは完全に合理的です(IMO)。私は個人的にアサーションをあまり使用しませんが、ある程度個人的な好みの問題です。 (アサーションの賛否両論は確かに存在する可能性がありますが、選好を完全に排除するのに十分明確ではありません。)
Javaアサーションは、Java例外と例外処理の上に構築されます。実際、Javaアサーションが失敗すると、結果はAssertionError例外になり、次のようにキャッチできます。その他のJava例外。例外とアサーションの主な違いは次のとおりです。
Java言語は、アサーションの構文サポートをassert
ステートメントの形式で提供します。以下を比較してください。
_if (x != y) {
throw new SomeException("x != y");
}
assert x != y;
_
最も重要なことは、Javaを使用すると、JVMの起動時にアサーションチェックをグローバルに、または個々のクラスで有効または無効にすることができます。
注:一部の人々はalwaysアサーションチェックをオフにして本番コードを実行する必要があると言います。私はこれを総括的な意見として反対する傾向があります。プロダクションコードが安定していることがわかっており、そのパフォーマンスの最後のビットを絞り出す必要がある場合は、アサーションをオフにすることをお勧めします。しかし、(たとえば)10%のパフォーマンスヒットが実際の問題ではない場合、別の方法が継続してデータベースが破損している場合、アサーションエラーでアプリケーションが停止することを望みます。
@MarioOrtegónはこうコメントしました:
「オフにする」のは、アサーションを使用して、実装をよく知られているが遅いアルゴリズムと比較することにより、最適化されたアルゴリズムの結果を検証できるためです。そのため、開発では、その
O(N^3)
メソッドを呼び出して、O(log N)
アルゴリズムが意図したとおりに機能することをアサートしてもかまいません。しかし、これは実稼働環境では望ましくないものです。
実稼働環境でアサーションをオフにするのはグッドプラクティスであるかどうかにかかわらず、有効にするとパフォーマンスに大きな影響を与えるアサーションを記述することは間違いなくバッドプラクティスです。どうして?というのは、本番環境で(問題をトレースするために)アサーションを有効にしたり、ストレス/容量テストでアサーションを有効にしたりするオプションがなくなったからです。私の意見では、O(N^3)
事前/事後条件テストを実行する必要がある場合、ユニットテストで実行する必要があります。
例外は、実装が予想されるまたは予期しないエラーなしで実行されているかどうかをチェックするメカニズムです。したがって、例外は基本的にアプリケーションの実行中に予期しない条件をより良い方法で処理するために使用されるため、例外を効果的に使用すると堅牢なアプリケーションになります。
アサーションは、アプリケーションの一部の機能の実装の一部であってはなりません。それらは仮定を検証するためにのみ使用されるべきです-ソリューションを設計するときに仮定したものが実際にも実際に有効であることを確認するためだけです。
参照: http://geekexplains.blogspot.com/2008/06/asserions-in-Java-assertions-vs.html
アサーションは例外に非常に似ており、実際には例外と同様に問題にフラグを立てますが、例外とは異なり、代替の実行パスは提案しませんが、単に失敗します。同じことを行うことができ、さらに例外を使用してさらに多くのことができる場合、なぜアサーションを使用しますか?
問題を修正する必要がない場合に使用し、実際には最初の場所で発生しないようにしてください。これは最初は奇妙に聞こえます。すべての潜在的な問題からコードを保護したくないのですか?通常はそうです。しかし、そうしない場合があります。このケースは「契約による設計」と呼ばれます。
銀行の申請書を書いているとしましょう。開発者として、可能性のあるすべての財務状況をサポートすることはできません。したがって、コーディングを開始する前に、このアプリケーションがサポートする有効な範囲を提供する仕様書を銀行から入手します。したがって、アプリケーションは契約によって設計されます(銀行からの仕様による)。この契約は、アプリケーションが機能するために常に真である必要がある基本原則を定義します。これらの基本原則は「不変式」と呼ばれます(変更できないため)。契約による設計は、開発者としてのあなたの人生を簡素化します-あなたは、契約で定義された作業範囲をサポートする責任があります。
コード内のこれらの不変式の値を確認することは重要ですが、それらを例外であるかのように確認して回避することはできません。それらが間違っている場合-入力が契約上の義務を果たしていないため、失敗する必要があります。
興味深いのは、重要な場所にアサーションを入れないと不変式が無効になると、コードはとにかく失敗するということです。理由が分からないだけです。要約すると、アサーションは不変条件の検証に使用されます。それらは、「契約による設計」の原則と密接に関連しています。それらを使用して問題をデバッグします。これが、本番環境でオフになっている理由です。
別のユースケース:完全に信頼できない外部ライブラリに依存している場合、呼び出すときにアサートステートメントを使用することができます。
また、アサーションを例外の迅速で汚れた代替として使用することもあります(簡単に実行できるため)が、概念的には適切なことではありません。
Assertの適切な使用例:
assert flibbles.count() < 1000000; // too many flibbles indicate something is awry
log.warning("flibble count reached " + flibbles.count()); // log in production as early warning
私は個人的に、Assertはonlyのみ使用する必要があると思います望ましい制限の外側にあるが、それが合理的であると確信できるとき続行しても安全です。他のすべての状況(私が考えていない状況を自由に指摘してください)では、例外を使用して激しく失敗します。
私にとって重要なトレードオフは、破損を回避してトラブルシューティングを容易にするために、例外を使用してライブ/実稼働システムを停止するか、またはテスト/デバッグバージョンで気付かれずに続けることは決してできない状況に遭遇したかどうかです本番環境での継続を許可されます(もちろん警告を記録します)。
cf. http://c2.com/cgi/wiki?FailFast この回答のc#コピーも参照してください: Debug.Assert vs. Specific Thrown Exceptions
アサーションと例外処理はどちらもプログラムの正確性を保証し、論理エラーを回避できます。
しかし、アサーションはプログラマーの希望に応じて有効または無効にできます。
コンパイラで「Java -ea JavaFileName」または「Java -enableasserations JavaFileName」を使用すると、アサーションでコンパイルできます
プログラマがそれを必要としない場合、「Java -da JavaFileName」または「Java -disableasserations JavaFileName」アサーションを無効にできます。
この機能は例外処理ではありません
アサートはデバッグのみを目的としており、そのトリガー条件は発生しません(存在しない場合はNULLポインターなど)。
例外は、常に発生する可能性がある特殊なシステムイベントです:FileNotFound、ConnectionToServerLostなど。
アサーションは、例外がプログラムの実行中にチェックされる特定の条件をチェックしてプログラムが終了しないようにする一方で、アサート機能を有効にすることによってのみ、実行時にチェックされる必要な仮定のデバッグに使用されます。