web-dev-qa-db-de.com

Was ist die beabsichtigte Verwendung von IllegalStateException?

Dies hat sich heute in einem Gespräch mit einem Kollegen ergeben.

Die Javadocs für Javas IllegalStateException geben an, dass es:

Zeigt an, dass eine Methode zu einem unzulässigen oder unangemessenen Zeitpunkt aufgerufen wurde. Mit anderen Worten, die Java-Umgebung oder Java-Anwendung befindet sich nicht in einem geeigneten Zustand für die angeforderte Operation.

Und effektives Java sagt (Artikel 60, Seite 248):

Eine weitere häufig wiederverwendete Ausnahme ist IllegalStateException. Dies ist im Allgemeinen die Ausnahme, die ausgelöst werden soll, wenn der Aufruf aufgrund des Status des empfangenden Objekts unzulässig ist. Dies wäre beispielsweise die Ausnahme, die ausgelöst werden soll, wenn der Aufrufer versucht hat, ein Objekt zu verwenden, bevor es ordnungsgemäß initialisiert wurde.

Es scheint, dass es hier ein bisschen Diskrepanz gibt. Im zweiten Satz der Javadocs klingt es so, als könnte die Ausnahme eine sehr weit gefasste Bedingung bezüglich des Java-Ausführungsstatus beschreiben. Die Beschreibung in Effective Java klingt jedoch so, als würde sie für Bedingungen verwendet, die sich speziell auf den Status des Objekts beziehen, dessen Methode wurde aufgerufen.

Die Verwendungen, die ich im JDK (z. B. Collections, Matcher) und in Guava gesehen habe, scheinen definitiv in die Kategorie zu fallen, über die Effective Java spricht ("Dieses Objekt befindet sich in einem Zustand, in dem diese Methode nicht aufgerufen werden kann"). Dies scheint auch konsistent zu sein mit IllegalStateExceptions Geschwister IllegalArgumentException.

Gibt es legitime IllegalStateException-Verwendungen im JDK, die sich auf die "Java-Umgebung" oder "Java-Anwendung" beziehen? Oder befürworten Best Practices-Anleitungen, es für den umfassenderen Ausführungsstatus einzusetzen? Wenn nicht, warum, zum Teufel, werden die Javadocs so formuliert? ;)

69
Andrew McNamee

Hier ist eine besonders legitime Verwendung dieser Ausnahme in JDK (siehe: URLConnection.setIfModifiedSince(long) unter 300+ anderen Verwendungen davon:

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

Ich denke, das Beispiel ist ziemlich klar. Wenn sich das Objekt in einem bestimmten Status befindet ("Already connected"), sollten einige Operationen nicht aufgerufen werden. In diesem Fall können beim Herstellen der Verbindung einige Eigenschaften nicht festgelegt werden.

Diese Ausnahme ist besonders nützlich, wenn Ihre Klasse einen Status (State Machine?) Hat, der sich im Laufe der Zeit ändert, wodurch einige Methoden irrelevant oder unmöglich sind. Stellen Sie sich eine Car-Klasse vor, die über die Methoden start(), stop() und fuel() verfügt. Während der Aufruf von start() zweimal nacheinander wahrscheinlich nichts Falsches ist, ist das Betanken eines gestarteten Autos sicherlich eine schlechte Idee. Das heißt, das Auto befindet sich in einem falschen Zustand.

Eine gute API sollte nicht zulassen, dass Methoden im falschen Status aufgerufen werden, sodass derartige Probleme zur Kompilierungszeit und nicht zur Laufzeit erkannt werden. In diesem speziellen Beispiel sollte die Verbindung zu einer URL ein anderes Objekt mit einer Teilmenge von Methoden zurückgeben, die alle nach dem Verbinden gültig sind.

38

Hier ist ein Beispiel im JDK. Es gibt eine private Paketklasse namens Java.lang.Shutdown. Wenn das System heruntergefahren wird und Sie versuchen, einen neuen Hook hinzuzufügen, wird die IllegalStateException ausgelöst. Man könnte argumentieren, dass dies die Kriterien der "Javadoc" -Anleitung erfüllt - da sich die Java-Umgebung im falschen Zustand befindet.

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;
        }
    }

Es zeigt jedoch auch, dass es wirklich keinen Unterschied zwischen der "Javadoc" -Richtlinie und der "Effective Java" -Richtlinie gibt. Aufgrund der Art und Weise, wie das Herunterfahren implementiert wird, wird das Herunterfahren der JVM in einem als State bezeichneten Feld gespeichert. Daher erfüllt es auch die "Effective Java" -Anweisung für die Verwendung von IllegalStateException, da das Feld "state" Teil des Status des empfangenden Objekts ist. Da sich das empfangende Objekt (Herunterfahren) im falschen Status befindet, wird die IllegalStateException ausgelöst.

Meiner Meinung nach sind die beiden Beschreibungen, wann IllegalStateException verwendet werden soll, konsistent. Die effektive Java-Beschreibung ist etwas praktischer, das ist alles. Für die meisten von uns ist die Klasse, die wir gerade schreiben, der wichtigste Teil der gesamten Java-Umgebung. Darauf konzentriert sich der Autor. 

4
Guido Simone

Ich denke, wenn Sie die Verwendung von IllegalStateException sehen, würde ich sagen, wenn dies angemessener wäre. Diese Ausnahme wird in vielen Paketen verwendet

  • Java.net
  • Java.nio
  • Java.util
  • Java.util.concurrrent etc

Zum Angeben eines Beispiels ArrayBlockingQueue.add löst diese Ausnahme aus, wenn die Warteschlange bereits voll ist. Nun ist full der Zustand des Objekts und es wird zu unangemessenen oder illegalen Zeitpunkt aufgerufen

Ich denke, beides bedeutet gleich, aber unterschiedliche Formulierungen.

2
Amit Deshpande

Bei einer Bibliothek sollte eine IllegalStateException oder IllegalArgumentException ausgegeben werden, wenn ein Fehler aufgrund des Benutzercodes festgestellt wird, während die Bibliothek eine AssertionError werfen sollte, wenn ein Fehler aufgrund der eigenen Implementierung der Bibliothek entdeckt wird.

In den Tests der Bibliothek können Sie beispielsweise erwarten, dass die Bibliothek eine IllegalStateException auslöst, wenn die Reihenfolge der Methodenaufrufe falsch ist. Aber Sie werden niemals erwarten, dass die Bibliothek eine AssertionError wirft.

0
Yang Bo

Ich bin darauf mit:

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

Ich denke, es wird für mich nicht praktikabel sein, IllegalStateException anstelle von AssertionException hier zu werfen, obwohl dies in die Kategorie "Java-Umgebung" fällt.

0
antak

Hier gibt es keine "Diskrepanz". In Blochs Wortlaut ist nichts enthalten, was das, was in der JLS steht, ausschließt. Bloch sagt einfach, dass, wenn Sie den Umstand A haben, diese Ausnahme ausgelöst wird. Er ist nicht sagt, diese Ausnahme sei nur - in diesem Zustand. Die JLS sagt, dass diese Ausnahme ausgelöst wird, wenn A, B oder C. 

0
user207421