Was ist die beabsichtigte Verwendung von IllegalStateException?

Lesezeit: 8 Minuten

Dies kam heute in einer Diskussion mit einem Kollegen zur Sprache.

Die Javadocs für Java IllegalStateException sagen, dass es:

Signalisiert, dass eine Methode zu einem illegalen 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 (Punkt 60, Seite 248):

Eine weitere häufig wiederverwendete Ausnahme ist IllegalStateException. Dies ist im Allgemeinen die auszulösende Ausnahme, wenn der Aufruf aufgrund des Zustands des empfangenden Objekts illegal ist. Dies wäre beispielsweise die auszulösende Ausnahme, wenn der Aufrufer versucht, ein Objekt zu verwenden, bevor es ordnungsgemäß initialisiert wurde.

Hier scheint es eine kleine Diskrepanz zu geben. Der zweite Satz der Javadocs lässt es so klingen, als könnte die Ausnahme eine sehr breite Bedingung über den Java-Ausführungsstatus beschreiben, aber die Beschreibung in Effective Java lässt es so klingen, als würde sie für Bedingungen verwendet, die sich speziell auf den Status des Objekts beziehen, dessen Methode aufgerufen wurde.

Die Verwendungen, die ich im JDK gesehen habe (z. B. Sammlungen, Matcher) und in Guava scheinen definitiv in die Kategorie zu fallen, von der Effective Java spricht (“Dieses Objekt befindet sich in einem Zustand, in dem diese Methode nicht aufgerufen werden kann”). Dies scheint auch im Einklang 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-Practice-Leitfäden die Verwendung für den breiteren Ausführungsstatus? Wenn nicht, warum zum Teufel sind die Javadocs so formuliert? 😉

  • In einer vielleicht nicht verwandten Anmerkung habe ich StackOverflow’s bemerkt [illegalstatexception] Etikett sagt In Java, an exception that occurs when using multiple threads, whereby one thread modifies an object in a way that makes it incompatible with the use of that object in the second thread, thus putting the object into an illegal state.. Häh? Woher kommt das?

    – Andrew McNamee

    2. Oktober 2012 um 21:07 Uhr

  • Die “Java-Anwendung” ist diejenige, die Sie schreiben und die Sie verwenden können IllegalStateException dort (entweder direkt oder weil Sie zum Beispiel Guava verwenden). Wo ist die Diskrepanz?

    – Frank Pavageau

    2. Oktober 2012 um 21:07 Uhr

  • Das Tag-Wiki sieht falsch aus, ich habe eine Bearbeitung eingereicht, indem ich mich großzügig von dieser Frage entlehnt habe. Sie sollten die neue Version sehen, sobald sie die Peer-Review bestanden hat.

    – Verdienst

    2. Oktober 2012 um 21:46 Uhr

Benutzer-Avatar
Tomasz Nurkiewicz

Hier ist eine besonders legitime Verwendung dieser Ausnahme im JDK (siehe: URLConnection.setIfModifiedSince(long) unter mehr als 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. Befindet sich das Objekt in einem bestimmten Zustand (“Schon verbunden“), sollten einige Operationen nicht aufgerufen werden. In diesem Fall können einige Eigenschaften nicht festgelegt werden, wenn die Verbindung hergestellt wurde.

Diese Ausnahme ist besonders nützlich, wenn Ihre Klasse einen Zustand (Zustandsmaschine?) hat, der sich im Laufe der Zeit ändert, wodurch einige Methoden irrelevant oder unmöglich werden. Denken Sie an ein Car Klasse, die hat start(), stop() und fuel() Methoden. Beim Telefonieren start() zweimal nacheinander ist wahrscheinlich nichts falsch, aber ein gestartetes Auto zu tanken ist sicherlich eine schlechte Idee. Nämlich – Auto ist in einem falschen Zustand.

Eine wohl gute API sollte uns nicht erlauben, Methoden im falschen Zustand aufzurufen, sodass solche Probleme zur Kompilierzeit und nicht zur Laufzeit entdeckt werden. In diesem speziellen Beispiel sollte die Verbindung mit einer URL ein anderes Objekt mit einer Teilmenge von Methoden zurückgeben, die alle nach der Verbindung gültig sind.

  • Ich stimme Ihrer Antwort zu. Aber das erklärt nicht, warum Effectiva Java und Guava diese Ausnahme wie eine verwenden IllegalArgumentException

    – Zarathustra

    31. August 2015 um 15:11 Uhr

Benutzer-Avatar
Guido Simone

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“-Anleitung und der „Effective Java“-Anleitung gibt. Aufgrund der Art und Weise, wie Shutdown implementiert wird, wird die Herunterfahrbarkeit der JVM in einem Feld namens state gespeichert. Daher erfüllt es auch die „Effective Java“-Anleitung für die Verwendung von IllegalStateException, da das Feld „state“ Teil des Status des empfangenden Objekts ist. Da sich das empfangende Objekt (Shutdown) im falschen Zustand befindet, löst es die IllegalStateException aus.

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 der wichtigste Teil der gesamten Java-Umgebung die Klasse, die wir gerade schreiben, also konzentriert sich der Autor darauf.

  • Ah, ich mag dieses Beispiel! Das InternalError throw direkt unter die ISE zeigt auch, wie nützlich es ist, eine Unterscheidung zwischen „Du hast es vermasselt“ und „Ich habe es vermasselt“ zu treffen. Außerdem zeigt es, wie der statische Status (man könnte sagen, „Java-Anwendung“ oder „Java-Umgebung“) immer noch als Status zählt, soweit es ISEs betrifft.

    – Andrew McNamee

    4. Oktober 2012 um 21:42 Uhr


  • @AndrewMcNamee Das denke ich AssertionError wäre besser geeignet für Fälle, in denen ich weiß, dass ich es vermasselt habe. Es scheint eine zu sein InternalError nur weil es sich eher im JDK-Code als im Anwendungscode befindet – eine zweifelhafte Unterscheidung.

    – Ramón

    7. Oktober 2012 um 10:49 Uhr

  • Ja, dem stimme ich definitiv zu AssertionError; es scheint zu vermitteln “Ich habe es vermasselt” im Gegensatz zu “Du hast es vermasselt” (was ISE impliziert). Ich benutze es viel in der default Fall für switches. Meiner Meinung nach InternalError dient immer noch einem nützlichen Zweck; Die Person, die den Stack-Trace liest, weiß, dass sie davon ausgehen kann, dass “Whoa, das JDK vermasselt wurde”, aber die JDK-Autoren hätten es wahrscheinlich weglassen können.

    – Andrew McNamee

    8. Oktober 2012 um 14:41 Uhr


Ich denke, wenn Sie die Verwendung von sehen IllegalStateException Ich würde sagen, zweitens, wenn es angemessener ist. Diese Ausnahme wird in vielen Paketen verwendet

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent usw

Um ein Beispiel zu nennen ArrayBlockingQueue.add löst diese Ausnahme aus, wenn die Warteschlange bereits voll ist. Jetzt ist der Zustand des Objekts voll und es wird zu einem unpassenden oder illegalen Zeitpunkt aufgerufen

Ich denke, beides bedeutet dasselbe, aber unterschiedliche Formulierungen.

Benutzer-Avatar
Yang Bo

Bei einer Bibliothek sollte es eine werfen IllegalStateException oder IllegalArgumentException immer wenn es einen Fehler aufgrund des Benutzercodes erkennt, während die Bibliothek eine werfen sollte AssertionError immer dann, wenn es einen Fehler aufgrund der eigenen Implementierung der Bibliothek entdeckt.

Beispielsweise können Sie in den Tests der Bibliothek erwarten, dass die Bibliothek eine auslöst IllegalStateException wenn die Reihenfolge der Methodenaufrufe falsch ist. Aber Sie werden nie erwarten, dass die Bibliothek einen wirft AssertionError.

Benutzer-Avatar
Benutzer207421

Hier gibt es keine “Diskrepanz”. Nichts in Blochs Formulierung schließt aus, was in der JLS steht. Bloch sagt einfach, dass, wenn Sie den Umstand A haben, diese Ausnahme auslösen. Er ist nicht sagen, dass diese Ausnahme ausgelöst wird/sollte nur in diesem Zustand. Die JLS sagt, dass diese Ausnahme ausgelöst wird, wenn A, B oder C.

  • Ich schätze, das könnte man sagen. Aber andererseits, wenn es beabsichtigte Verwendungsumstände gab, die sich von den von ihm angegebenen Umständen unterschieden, dann ist das möglicherweise nicht so aussagekräftig, da es weniger spezifisch wäre. Mit anderen Worten, wenn ISE unter anderen Umständen als dem aktuellen Fall “Sie haben diese Methode bei mir aufgerufen, aber ich bin nicht in einem Zustand, in dem ich das tun kann” vorgesehen ist, ist es möglicherweise nicht so informativ. Aber zugegeben, ich glaube, ich mache hier Haarspalterei 😉

    – Andrew McNamee

    4. Oktober 2012 um 21:49 Uhr

  • @AndrewMcNamee I tat Sag das. Ich weiß nicht, was der Rest Ihres Kommentars überhaupt bedeutet, aber Sie versuchen, eine Diskrepanz herzustellen, wo keine besteht. Du begehst einen logischen Fehlschluss.

    – Benutzer207421

    18. November 2012 um 1:02 Uhr

Benutzer-Avatar
Antak

Ich bin darauf gestoßen mit:

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

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

  • Ich schätze, das könnte man sagen. Aber andererseits, wenn es beabsichtigte Verwendungsumstände gab, die sich von den von ihm angegebenen Umständen unterschieden, dann ist das möglicherweise nicht so aussagekräftig, da es weniger spezifisch wäre. Mit anderen Worten, wenn ISE unter anderen Umständen als dem aktuellen Fall “Sie haben diese Methode bei mir aufgerufen, aber ich bin nicht in einem Zustand, in dem ich das tun kann” vorgesehen ist, ist es möglicherweise nicht so informativ. Aber zugegeben, ich glaube, ich mache hier Haarspalterei 😉

    – Andrew McNamee

    4. Oktober 2012 um 21:49 Uhr

  • @AndrewMcNamee I tat Sag das. Ich weiß nicht, was der Rest Ihres Kommentars überhaupt bedeutet, aber Sie versuchen, eine Diskrepanz herzustellen, wo keine besteht. Du begehst einen logischen Fehlschluss.

    – Benutzer207421

    18. November 2012 um 1:02 Uhr

1200230cookie-checkWas ist die beabsichtigte Verwendung von IllegalStateException?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy