アサーションを使用する場合と例外を使用する場合


121

ほとんどの場合、例外を使用してコード内の条件を確認しますが、アサーションを使用するのに適切なタイミングはいつですか。

例えば、

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

ここにアサーションがどのように適合するかを教えていただけますか?アサーションを使用する必要がありますか?

量産コードではアサーションを使用せず、単体テストでのみアサーションを表示するようです。私はほとんどの場合、例外を使用して上記のようなチェックを実行できることを知っていますが、「専門的に」それを行う適切な方法を知りたいです。

回答:


81

アサーションは発生してはならないことを確認するために使用する必要がありますが、例外は発生する可能性があることを確認するために使用する必要があります。

たとえば、関数は0で除算する可能性があるため、例外を使用する必要がありますが、アサーションを使用してハードドライブが突然消えることを確認できます。

アサーションはプログラムの実行を停止しますが、例外はプログラムの実行を継続させます。

if(group != null)これはアサーションではなく、単なる条件です。


3
「アサーションを使用して、ハードドライブが突然消えることを確認することができます」-これは正しくないと思います:開発中にこれを処理したいのに、本番環境では処理しない(アサーションが通常無効になっている)のはなぜですか?
ヘルマン

71
ハードドライブに関するコメントが間違っています。アサーションは、コードロジックのエラーをチェックするためのものです。それらを使用して、自分が制御できないものをチェックすることは決してありません。覚えておいて、アサーションが、それはあなたのコードが間違っていることを意味失敗した場合
Ian Goldby 2013年

1
@Mariusあなたの条件文は次のようなアサーションで置き換えることができます:assert group!= null
IgorGanapolsky

1
ハードドライブの例があなた自身の哲学と矛盾するため、反対票を投じました。(コードの観点から)「消える」ハードドライブは、実際には、起こりそうなことではなく、実際に発生する可能性があります。@IanGoldbyが言うように、アサーションはコードによって制御されるものに完全に依存する必要があります。
Vicky Chijwani

Gregory Pakoszが投稿した方がはるかに良い答えです。その投稿を読んでください。
ormurin

169

私の頭の中では(リストは不完全かもしれず、コメントに収まらないほど長すぎる)、私はこう言うでしょう:

  • パブリックまたは保護されたメソッドとコンストラクターに渡されたパラメーターをチェックするときに例外を使用する
  • ユーザーと対話するとき、またはクライアントコードが例外的な状況から回復することを期待するときに例外を使用する
  • 例外を使用して発生する可能性のある問題に対処する
  • プライベート/内部コードの前提条件、事後条件、および不変条件をチェックするときにアサーションを使用する
  • アサーションを使用して、自分自身または開発者チームにフィードバックを提供する
  • 発生する可能性が非常に低いことを確認するときにアサーションを使用します。それ以外の場合は、アプリケーションに重大なフローがあることを意味します
  • アサーションを使用して、(おそらく)真実であるとわかっていることを述べる

つまり、例外はアプリケーションの堅牢性に対応し、アサーションはその正確性に対応します。

アサーションは安価に作成できるように設計されており、ほとんどどこでも使用でき、私はこの経験則を使用しています。アサーションステートメントが愚かであるほど、価値が高くなり、情報が埋め込まれます。正しく動作しないプログラムをデバッグするときは、経験に基づいて、より明白な失敗の可能性を確実に確認します。次に、起こり得ない問題をチェックします。これは、アサーションが非常に役立ち、時間を節約するまさにその時です。


53
私はあなたがこれを言った方法が好きです:例外はアプリケーションの堅牢性に対処し、アサーションはその正確性に対処します。
M.ダドリー

私はこれを自分のサイトにクロスポストしました:pempek.net/articles/2013/11/16/assertions-or-exceptions
Gregory Pakosz

あなたがC ++カスタムアサートライブラリを探すために起こる場合と、私は解放さgithub.com/gpakosz/Assert
グレゴリーPakosz

26

アサーションは実行時にパラメータを使用して無効にでき、デフォルトでは無効になっていることを覚えておいてくださいでになっているので、デバッグ以外の目的で使用しないでください。

また、assertに関するOracleの記事を読んで、assertを使用する(または使用しない)ケースをさらに確認てください。


Hue hue hueなぜ私のコードはEclipseで失敗するのかと思っていましたが、コマンドラインでは問題なく実行されていました。
スティーブ

15

原則として:

  • 内部整合性チェックにはアサーションを使用して、誰かがそれらをオフにしてもまったく関係がない場合。(このjavaコマンドはデフォルトですべてのアサーションをオフにすることに注意してください。)
  • オフにしてはいけないあらゆる種類のチェックには、定期的なテストを使用してください。これに、バグによって引き起こされる潜在的な損傷から保護するための防御チェック、およびユーザーまたは外部サービスによって提供される検証データ/要求/あらゆるものが含まれます。

あなたの質問の次のコードはスタイルが悪くバグがある可能性があります

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

問題は、例外がグループが見つからなかったことを意味することを知らないことです。service()呼び出しが例外をスローしたか、呼び出しが戻っnullたためにが発生した可能性もありますNullPointerException

「予期される」例外をキャッチするときは、予期している例外のみをキャッチする必要があります。捕捉することでjava.lang.Exception(特にログに記録しないことにより)、問題の診断/デバッグが困難になり、アプリがより多くの損害を与える可能性があります。


4

さて、マイクロソフトに戻ると、推奨事項は、公開するすべてのAPIで例外をスローし、内部のコードについて行うあらゆる種類の仮定でアサートを使用することでした。少し緩い定義ですが、線を引くのは各開発者次第だと思います。

例外の使用に関しては、名前が示すように、その使用法は例外的であるべきなので、上記のコードの場合、getGroup呼び出しはnull場合、サービスが存在しない場合ます。例外は、ネットワークリンクがダウンした場合などにのみ発生します。

結論としては、アサートと例外の境界を定義するのは、各アプリケーションの開発チームに少し任されていると思います。


私見、そのような推奨事項の問題は、APIのパブリック部分とプライベート部分の境界がかなり固定されている限り問題ないということです。新しいコードを開発している場合、その境界はしばしばかなり流動的です...
Len Holgate

はい、あなたが正しい。これはガイドラインですが、結局のところ、プログラマーの感性に委ねられています。これらには究極の定義行があるとは思わないので、さまざまなコードのロードを読み取って、正しいと思うものをそのまま使用すると思います。
rui

3

このドキュメントによるとhttp://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general、「assertステートメントは非公開の前提条件、事後条件、およびクラス不変式に適していますチェック。パブリック前提条件チェックは、IllegalArgumentExceptionやIllegalStateExceptionなど、特に文書化された例外が発生するメソッド内のチェックによって実行される必要があります。

:あなたが前提条件、事後条件とクラス不変条件についての詳細をお知りになりたい場合は、このドキュメントをチェックhttp://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditionsを。また、アサーションの使用例も含まれています。


1

nullのテストでは、問題の原因となるnullのみをキャッチしますが、try / catchを使用するとエラーがキャッチされます。

おおまかに言って、try / catchの方が安全ですが、少し遅く、発生する可能性のあるすべての種類のエラーをキャッチするように注意する必要があります。だから私はtry / catchを使うと言います-ある日getGroupコードが変わるかもしれません、そしてあなたはただもっと大きなネットを必要とするかもしれません。


1

この単純な違いを使用しながら使用できます。アサーションは主に実行時のデバッグの目的で使用され、仮定が検証されているかどうかを確認するために、チェックされたエラーとチェックされていないエラーと呼ばれる予期されるエラーと予期しないエラーをチェックするために例外が使用されます。


1

私はあなたの質問に少し戸惑っています。アサーション条件が満たされない場合、例外がスローされます。紛らわしいことに、これはAssertionErrorと呼ばれます。非常に類似した状況でスローされる(たとえば)IllegalArgumentExceptionのように、チェックされていないことに注意してください。

Javaでアサーションを使用する

  1. 条件/スローブロックを記述するより簡潔な手段です
  2. JVMパラメータを介してこれらのチェックをオン/オフにすることができます。通常、これらのチェックは実行時のパフォーマンスに影響を与えたり、同様のペナルティがない限り、常にオンのままにします。

AssertionErrorは、RuntimeExceptionではなく、Errorのサブクラスです。
スティーブンC

ああ。もちろん。チェック/チェック解除を考えていました。修正済み
ブライアンアグニュー

(論争の的になる観点から)それはアサーションが何であるかを説明しますが、それらを正確にいつ使うべきかは説明しません。
カールリヒター

1

次のリンクにあるSunのドキュメントのセクション6.1.2(アサーションとその他のエラーコード)を参照してください。

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

このドキュメントは、アサーションを使用するときに私が見た中で最高のアドバイスを提供します。文書からの引用:

「経験則として、忘れたい例外的なケースにはアサーションを使用する必要があります。アサーションは、必要のない状態や状態を処理し、忘れる最も早い方法です。扱う。"


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.