必要なメソッドパラメータにassertまたはIllegalArgumentExceptionを使用する方が良いですか?


87

Javaでは、どちらがより強く推奨されますか?その理由は?どちらのタイプも例外をスローするため、それらの処理に関しては同じです。assert少し短くなりますが、それがどれほど重要かはわかりません。

public void doStuff(Object obj) {
    assert obj != null;
    ...
}

public void doStuff(Object obj) {
    if (obj == null) {
        throw new IllegalArgumentException("object was null");
    }
    ...
}

私はobj.hashCode()代わりにシンプルな方が好きです;-)
Marco

回答:


118

気をつけて!

アサーションは、コードのコンパイル時に「アサーションを有効にする」ことを明示的に指定しない限り、実行時に削除されます。Javaアサーションはプロダクションコードでは使用されず、プライベートメソッドに限定する必要があります例外とアサーションを参照)。プライベートメソッドは開発者のみが知っており、使用することが期待されています。また、not を拡張するAssertionErrorassertスローします。これは通常、非常に異常なエラー(回復が困難な「OutOfMemoryError」など)があることを示しますが、処理できないことが予想されます。ErrorException

「アサーションを有効にする」フラグを削除し、デバッガーで確認すると、IllegalArgumentException throw callを踏まないことがわかります。このコードはコンパイルされていないため(「ea」が削除されると)

public / protectedメソッドには2番目の構成を使用することをお勧めします。1行のコードで何かをしたい場合は、少なくとも1つの方法を知っています。私は個人的に、引数をチェックするためのいくつかのメソッドを持ち、失敗したときに "IllegalArgumentException"をスローするSpring FrameworkAssertクラスを使用しています。基本的に、あなたがすることは:

Assert.notNull(obj, "object was null");

...実際、2番目の例で記述したコードとまったく同じコードを実行します。以下のようないくつかの他の有用な方法がありhasTexthasLengthそこに。

必要以上のコードを書くのは好きではないので、書き込まれた行の数を2つ減らすとうれしいです(2行> 1行):-)


ああ、アサーションが削除されることを忘れていました!素晴らしい答え。他の何かが入ってくるかどうかを確認するために少し待って、それを受け入れます:)
Daenyth

2
コンパイル時にアサーションを削除するフラグはないことに注意してください(ただし、アサーションは条件付きコンパイルによって削除される場合があります)。アサーションはデフォルトで実行時に無効になります(JVMはそれらをNOOPとして扱うと思います)がjava -ea、プログラムで有効にできます。@Jalayn私は、彼らがために有用である生産コードでアサーションを持つことが、完全に有効であると考える分野でのデバッグ
ジャスティン・ミュラー

@ Jalayn、-1 コンパイラーはアサーションコードを削除しませ。cmdを実行しない限り、それらは実行されませんjava -ea
Pacerier 14

5
使用できる場合、Springフレームワークは必要ありませんObjects.requreNonNull
cambunctious

46

例外を使用する必要があります。アサーションを使用すると、機能の誤用になります。

未確認の例外はライブラリのユーザーのプログラミングエラーを検出するように設計されており、アサーションは独自のロジックのエラーを検出するように設計されています。これらは混在してはならない個別の問題です。

たとえば、アサーション

assert myConnection.isConnected();

は、「このアサーションに至る各コードパスが確実にmyConnection接続されることを知っています。上記のコードが有効な接続を取得できなかった場合、このポイントに到達する前に例外を返すか戻る必要があります。」

一方、チェック

if (!myConnection.isConnected()) {
    throw new IllegalArgumentException("connection is not established");
}

「接続を確立せずにライブラリを呼び出すと、プログラミングエラーになる」ことを意味します。


1
この情報は非常に役立ちますが、アサートメソッドにバグを導入する可能性があることを指摘しているため、Jalaynを受け入れています。
デニーズ

4
優れた点「未チェックの例外は、ライブラリのユーザーのプログラミングエラーを検出するように設計されているのに対し、アサーションは、独自のロジックのエラーを検出するように設計されています。
アシムガッファー

本当ですが、これはOPがライブラリを書いていると仮定しています コードが内部使用専用の場合、アサートは受け入れられます。
user949300

11

null有効なパラメーター値として許可されない関数を作成している場合は、@Nonnull注釈に署名を追加しObjects.requireNonNull、引数が存在するかどうかを確認し、存在する場合はnullスローするNullPointerException必要があります。@Nonnull注釈は文書化のためのものであり、いくつかのケースでは、コンパイル時に役立つ警告を提供します。null実行時に渡されることを妨げません。

void doStuff(@Nonnull Object obj) {
    Objects.requireNonNull(obj, "obj must not be null");

    // do stuff...
}

アップデート:@Nonnull注釈はJavaの標準ライブラリの一部ではありません。代わりに、サードパーティのライブラリから多数の競合する標準があります(どの@NotNull Javaアノテーションを使用すべきかを参照してください)。それは、それが標準ではないというだけで、それを使用するのが悪い考えであることを意味しません。


指摘してくれてありがとうObjects.requireNonNull()、これは私にとっては新しいことでした。同様の「requireTrue()」または「requireEqual()」メソッドがどこにあるか知っていますか?SpringのAssertに対しては何もありませんが、誰もがそれを使用しているわけではありません。
user949300

@ user949300 Objects.requireNonNull()は引数の検証用です。引数がtrue何かである必要がある場合、その引数は無意味です。不正な引数以外のエラーの場合、エラーをより正確に記述する必要がthrowありExceptionます。JUnitもありますAssertが、これはテスト用です。
camな

私はもっ​​と、たとえば平方根関数Objects.requireTrue(x >= 0.0);、またはハッシュについてObjects.requireEquals(hash.length == 256)
考えていました-user949300

どの@Nonnullを使用する必要がありますか?javax.validation.constraints.NotNull?
アグイド

Eclipse JDTアノテーションを使用するのは、賢い人が作成しているからです:)。ドキュメント:help.eclipse.org/neon/…-IntelliJを使用してそれらを使用するように構成することもできます。
-koppor

2

私は常にアサーションよりもIllegalArgumentExceptionをスローすることを好みます。

アサーションは、テスト結果を確認/アサートするために、主にJUnitまたは他のテストツールで使用されます。そのため、メソッドがテストメソッドであるという誤った印象を他の開発者に与える場合があります。

また、メソッドに不正または不適切な引数が渡されたときにIllegalArgumentExceptionをスローすることは理にかなっています。これは、Java開発者が従う例外処理規則とより一貫しています。


5
アサーションはJUnitの約40年前でした-CプログラマーにASSERTマクロについて尋ねてください。
JBRWilkinson

3
この質問はcに関するものではありません。そのJavaについて。だから私はJavaのコンテキストで答えました。
rai.skumar

assert(予約キーワード)とAssert(JUnitクラス)を混同しないでください。これらは両方とも変数のチェックに使用されますが、それ以外は2つの非常に異なるものであり、非常に異なる動作をします。
ニュートピア

1

2番目のIMOは、より多くの情報を提供し、さらに拡張して(たとえば、例外クラスを拡張することで)さらに有益になるため、やや優れています。また、理解しやすいネガティブ比較を使用しません。


1

アサートはあまり使用しませんが、Lombock @NonNullでの一般的なアプローチ:https ://projectlombok.org/features/NonNull

ロンボクの実装:import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    this.name = person.getName();
  }
}

Javaバージョン:

 import lombok.NonNull;

public class NonNullExample extends Something {
  private String name;

  public NonNullExample(@NonNull Person person) {
    super("Hello");
    if (person == null) {
      throw new NullPointerException("person");
    }
    this.name = person.getName();
  }
}

ロンボクは私がいたるところで使っている本当に素晴らしいライブラリです

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