1. ホーム
  2. java

[解決済み] IllegalArgumentExceptionはどのような場合にスローされるのですか?

2022-03-01 21:11:58

質問

実行時例外処理なので、控えめにしたほうがいいのではと心配です。
標準的な使用例です。

void setPercentage(int pct) {
    if( pct < 0 || pct > 100) {
         throw new IllegalArgumentException("bad percent");
     }
}

しかし、それだと次のようなデザインを強いられるような気がします。

public void computeScore() throws MyPackageException {
      try {
          setPercentage(userInputPercent);
      }
      catch(IllegalArgumentException exc){
           throw new MyPackageException(exc);
      }
 }

チェックされた例外に戻すため。

なるほど、でもそれで行こう。 悪い入力をすると、ランタイムエラーが発生します。 だからまず第一に、それは実は一律に実装するのがかなり難しいポリシーで、全く逆の変換をしなければならない可能性があるからです。

public void scanEmail(String emailStr, InputStream mime) {
    try {
        EmailAddress parsedAddress = EmailUtil.parse(emailStr);
    }
    catch(ParseException exc){
        throw new IllegalArgumentException("bad email", exc);
    }
}

さらに悪いことに、チェック中に 0 <= pct && pct <= 100 しかし、電子メールアドレスのような高度なデータ、あるいはデータベースと照合する必要のあるデータについては、そうではありません。

つまり、基本的に私が言いたいのは、「Security」の使用に関する意味のある一貫したポリシーが見当たらないということです。 IllegalArgumentException . これは使うべきではなく、独自のチェックされた例外にこだわるべきと思われます。 これを投げる良いユースケースは何でしょうか?

解決方法は?

治療 IllegalArgumentException として 前提条件 を確認し、設計方針を検討する。 パブリック・メソッドは、それ自身の前提条件を知っていると同時に、それを公的に文書化する必要があります。

この例は正しいということになりますね。

void setPercentage(int pct) {
    if( pct < 0 || pct > 100) {
         throw new IllegalArgumentException("bad percent");
     }
}

EmailUtilが不透明の場合 つまり、前提条件をエンドユーザーに説明できない何らかの理由がある場合、チェックされた例外が正しいのです。この設計を修正したのが第2版です。

import com.someoneelse.EmailUtil;

public void scanEmail(String emailStr, InputStream mime) throws ParseException {
    EmailAddress parsedAddress = EmailUtil.parseAddress(emailStr);
}

EmailUtilが透過的である場合 例えば、問題のクラスが所有するプライベート・メソッドである可能性があります。 IllegalArgumentException は、その前提条件が関数のドキュメントに記述されている場合に限り、 正しいと言えます。これも正しいバージョンです。

/** @param String email An email with an address in the form [email protected]
 * with no nested comments, periods or other nonsense.
 */
public String scanEmail(String email)
  if (!addressIsProperlyFormatted(email)) {
      throw new IllegalArgumentException("invalid address");
  }
  return parseEmail(emailAddr);
}
private String parseEmail(String emailS) {
  // Assumes email is valid
  boolean parsesJustFine = true;
  // Parse logic
  if (!parsesJustFine) {
    // As a private method it is an internal error if address is improperly
    // formatted. This is an internal error to the class implementation.
    throw new AssertError("Internal error");
  }
}

このデザインは、どっちでもいいんです。

  • 前提条件を記述するのが面倒な場合、あるいはメールが有効かどうかわからないクライアントがこのクラスを使うことを想定している場合は ParseException . ここでのトップレベルのメソッドは scanEmail これは、エンドユーザが未審査のメールを送信することを意図していることを示唆しているので、おそらく正しいでしょう。
  • 関数のドキュメントに前提条件を記述することができ、クラスが無効な入力を意図しないため、プログラマエラーが表示される場合、次のように使用します。 IllegalArgumentException . チェックはされませんが、このチェックは関数のドキュメントであるJavadocに移動し、クライアントはこのドキュメントを遵守することが期待されます。 IllegalArgumentException クライアントが自分の引数が違法であることを事前に知ることができないのは、間違っています。

IllegalStateExceptionに関する注意点 : これは、「このオブジェクトの内部状態(プライベートなインスタンス変数)が、このアクションを実行できない」ことを意味します。 IllegalArgumentException クライアントコールがオブジェクトの状態に矛盾があることを知る術がない場合。チェックされた例外よりも優先される場合について、私は良い説明を持っていません。たとえば、2回初期化された場合や、データベース接続が回復しないまま失われた場合などがその例ですが、このような場合です。