web-dev-qa-db-ja.com

IllegalStateExceptionの使用目的は何ですか?

これは本日、同僚との議論の中で出てきました。

JavaのJavadoc IllegalStateException は次のように述べています。

違法または不適切な時間にメソッドが呼び出されたことを通知します。つまり、Java環境またはJavaアプリケーションは、要求された操作に対して適切な状態ではありません。

そして、有効なJavaは(Item 60、page 248)と言います:

別の一般的に再利用される例外は、IllegalStateExceptionです。これは一般に、受信オブジェクトの状態が原因で呼び出しが無効である場合にスローする例外です。たとえば、これは、呼び出し側が適切に初期化される前にオブジェクトを使用しようとした場合にスローする例外です。

ここには少し矛盾があるようです。 javadocsの2番目の文は、例外がJava実行状態に関する非常に広範な条件を説明できるように聞こえますが、Effective Javaメソッドが呼び出されたオブジェクトの状態の状態に特に関連する条件に使用されているように聞こえます。

JDK(例、コレクション、Matcher)やグアバで見た使用法は、確実にEffective Java talks about( "このオブジェクトはこのメソッドを呼び出せない状態」)。これは、IllegalStateExceptionの兄弟IllegalArgumentExceptionと一致しているようにも見えます。

「Java環境」または「Javaアプリケーション」に関連する正当なIllegalStateExceptionの使用法がJDKにありますか?それとも、より広い実行状態にそれを使用することを推奨するベストプラクティスガイドはありますか?そうでない場合、なぜjavadocはそのように表現されていますか? ;)

73
Andrew McNamee

JDKでのこの例外の特に正当な使用法の1つを次に示します(300を超える他の使用法の中で URLConnection.setIfModifiedSince(long) を参照)

_public void setIfModifiedSince(long ifmodifiedsince) {
    if (connected)
        throw new IllegalStateException("Already connected");
    ifModifiedSince = ifmodifiedsince;
}
_

例はかなり明確だと思います。オブジェクトが特定の状態(「Already connected」)の場合、一部の操作は呼び出さないでください。この場合、接続が確立されたときに、一部のプロパティを設定できません。

この例外は、時間とともに変化する状態(状態マシン?)がクラスにあり、一部のメソッドが無関係または不可能になる場合に特に役立ちます。 start()stop()、およびfuel()メソッドを持つCarクラスについて考えてください。 start()を次々に2回呼び出すことはおそらく何も悪いことではありませんが、始動した車に燃料を供給することは確かに悪い考えです。すなわち-車は間違った状態にあります。

おそらく良いAPIでは、間違った状態でメソッドを呼び出すことはできません。そのような問題は、実行時ではなくコンパイル時に発見されます。この特定の例では、URLに接続すると、メソッドのサブセットを持つ別のオブジェクトが返されます。これらはすべて、接続後に有効です。

41

JDKの例を次に示します。 Java.lang.Shutdownと呼ばれるパッケージプライベートクラスがあります。システムがシャットダウンしているときに新しいフックを追加しようとすると、IllegalStateExceptionがスローされます。これは「javadoc」ガイダンスの基準を満たしていると主張することができます-それはJava環境が間違った状態にあるためです。

class Shutdown {    
...

   /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
    * but does not do any security checks.
    */
    static void add(int slot, Runnable hook) {
        synchronized (lock) {
            if (state > RUNNING)
                throw new IllegalStateException("Shutdown in progress");

            if (hooks[slot] != null)
                throw new InternalError("Shutdown hook at slot " + slot + " already registered");

            hooks[slot] = hook;
        }
    }

ただし、「javadoc」ガイダンスと「Effective Java」ガイダンスに実際には区別がないことも示しています。シャットダウンの実装方法により、JVMのシャットダウン状態はstateと呼ばれるフィールドに保存されます。したがって、「state」フィールドは受信オブジェクトの状態の一部であるため、IllegalStateExceptionをいつ使用するかについての「Effective Java」ガイダンスにも適合しています。受信オブジェクト(シャットダウン)の状態が間違っているため、IllegalStateExceptionがスローされます。

私の意見では、IllegalStateExceptionを使用する場合の2つの説明は一貫しています。 Effective Javaの説明はもう少し実用的です、それがすべてです。ほとんどの人にとって、Java環境全体の最も重要な部分は、今書いているので、それは著者が注目していることです。

4
Guido Simone

IllegalStateExceptionの使用法が見つかれば、もっと適切であれば2番目と言います。この例外は多くのパッケージで使用されます

  • Java.net
  • Java.nio
  • Java.util
  • Java.util.concurrrentなど

1つの例を指定するには ArrayBlockingQueue.add は、キューが既にいっぱいの場合にこの例外をスローします。これで、オブジェクトの状態はいっぱいになり、不適切または違法なときに呼び出されます

両方とも同じですが、言い回しの違いを意味すると思います。

2
Amit Deshpande

ライブラリを指定すると、ユーザーコードによるバグを検出するたびにIllegalStateExceptionまたはIllegalArgumentExceptionをスローする必要がありますが、ライブラリは、バグを検出するたびにAssertionErrorをスローする必要がありますライブラリの独自の実装に。

たとえば、ライブラリのテストでは、メソッド呼び出しの順序が間違っていると、ライブラリがIllegalStateExceptionをスローすることを期待できます。ただし、ライブラリがAssertionErrorをスローすることは決してありません。

1
Yang Bo

私はこれに遭遇しました:

try {
    MessageDigest digest = MessageDigest.getInstance("SHA-1");
    ...
} catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
}

「Java環境」カテゴリに分類されますが、IllegalStateExceptionの代わりにAssertionExceptionをここにスローするのは非現実的だと思います。

0
antak

ここには「矛盾」はありません。 Blochの言葉遣いには、JLSで述べられていることを除外するものは何もありません。 Blochは、状況Aがある場合、この例外をスローするだけだと言っています。彼はnotこの例外はこの条件でスローされるべきである/スローされるべきだと言っているonly JLSは、A、B、またはCの場合、この例外がスローされると言っています。

0
user207421