web-dev-qa-db-ja.com

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

Javaでは、どちらを強くお勧めしますか。また、その理由は何ですか。どちらのタイプも例外をスローするので、その点でそれらの処理は同じです。 assertは少し短いですが、それがどれほど重要かはわかりません。

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

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

注意!

Assertions は、コードのコンパイル時に「アサーションを有効にする」ことを明示的に指定しない限り、実行時に削除されます。 Javaアサーションはプロダクションコードでは使用せず、プライベートメソッドに限定する必要がありますException vs Assertion を参照)。プライベートメソッドは既知であり、開発者のみが使用することが想定されています。また、assertAssertionError をスローします。これはErrorではなくExceptionを拡張し、通常は非常に異常なエラー( "OutOfMemoryError"など)があることを示します回復するのは難しいですよね?)あなたは治療することができるとは期待されていません。

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

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

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

...実際には、2番目の例で記述したのとまったく同じコードを実行します。 hasTexthasLengthなどの便利なメソッドがいくつかあります。

必要以上に多くのコードを書くのが好きではないので、書き込む行数を2行減らすと嬉しいです(2行> 1行):-)

123
Jalayn

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

未チェックの例外はライブラリのsersのプログラミングエラーを検出するように設計されていますが、アサーションはyour ownロジックのエラーを検出するように設計されています。これらは混合してはならない個別の問題です。

たとえば、アサーション

assert myConnection.isConnected();

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

一方、チェック

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

「接続を確立せずにライブラリを呼び出すのはプログラミングエラーです」という意味です。

47
dasblinkenlight

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アノテーションを使用する必要がありますか? を参照)。それは、それを使用するのが悪い考えであることを意味するのではなく、それは標準ではありません。

11
cambunctious

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

アサーションは、主にJUnitまたはその他のテストツールで使用され、テスト結果をチェック/アサートします。そのため、あなたのメソッドがテストメソッドであると他の開発者に誤った印象を与える可能性があります。

メソッドに不正または不適切な引数が渡されたの場合、IllegalArgumentExceptionをスローすることも意味があります。これは、Java開発者が後に続く例外処理規則との整合性が高くなります。

2
rai.skumar

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

Lombokの実装: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();
  }
}

ロンボクは私がどこでも使用する本当に素晴らしいライブラリです

1
kensai

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

1
0lukasz0