Was ist die beabsichtigte Verwendung von IllegalStateException?

76

Dies kam heute in einem Gespräch mit einem Kollegen zum Ausdruck.

Die Javadocs für Java IllegalStateExceptiongeben an, 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 Effective Java sagt (Punkt 60, Seite 248):

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

Es scheint, dass es hier ein bisschen Diskrepanz gibt. 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 es für Bedingungen verwendet, die sich speziell auf den Zustand des Zustands des Objekts beziehen, dessen Methode wurde aufgerufen.

Die Verwendungen, die ich im JDK (z. B. Sammlungen 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 im Einklang mit IllegalStateExceptiondem Geschwister zu stehen IllegalArgumentException.

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

Andrew McNamee
quelle
4
In einem möglicherweise nicht verwandten Fall habe ich festgestellt, dass das [illegalstatexception] -Tag von StackOverflow besagt 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.. Huh? Woher kommt das?
Andrew McNamee
3
Die "Java-Anwendung" ist die, die Sie schreiben und die Sie dort verwenden können IllegalStateException(entweder direkt oder weil Sie beispielsweise Guava verwenden). Wo ist die Diskrepanz?
Frank Pavageau
4
Das Tag-Wiki sieht falsch aus. Ich habe eine Bearbeitung eingereicht, indem ich diese Frage großzügig übernommen habe. Sie sollten die neue Version sehen, sobald sie die Peer Review bestanden hat.
Meriton

Antworten:

43

Hier ist eine besonders legitime Verwendung dieser Ausnahme in 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. Wenn sich das Objekt in einem bestimmten Zustand befindet (" Bereits verbunden "), 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 (Statusmaschine?) Hat, der sich im Laufe der Zeit ändert und einige Methoden irrelevant oder unmöglich macht. Denken Sie an eine CarKlasse , die hat start(), stop()und fuel()Methoden. Wenn Sie start()zweimal nacheinander anrufen , ist das wahrscheinlich nichts Falsches, aber das Betanken eines gestarteten Autos ist sicherlich eine schlechte Idee. Das Auto befindet sich nämlich in einem falschen Zustand.

Eine wohl gute API sollte es uns nicht erlauben, Methoden im falschen Zustand aufzurufen, damit solche Probleme zur Kompilierungszeit und nicht zur Laufzeit entdeckt werden. In diesem Beispiel sollte das Herstellen einer Verbindung zu einer URL ein anderes Objekt mit einer Teilmenge von Methoden zurückgeben, die alle nach dem Herstellen einer Verbindung gültig sind.

Tomasz Nurkiewicz
quelle
1
Ich stimme Ihrer Antwort zu. Dies erklärt jedoch nicht, warum Effectiva Java und Guava diese Ausnahme wie einIllegalArgumentException
Zarathustra
4

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" -Richtlinie 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 Anleitung "javadoc" und der Anleitung "Effective Java" gibt. Aufgrund der Art und Weise, wie Shutdown implementiert wird, wird das Herunterfahren der JVM in einem Feld namens state gespeichert. Daher erfüllt es auch die "Effective Java" -Richtlinie 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, wird die IllegalStateException ausgelöst.

Meiner Meinung nach sind die beiden Beschreibungen, wann IllegalStateException verwendet werden soll, konsistent. Die Beschreibung von Effective Java 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. Darauf konzentriert sich der Autor.

Guido Simone
quelle
1
Ah, ich mag dieses Beispiel! Der InternalErrorWurf direkt unter der ISE zeigt auch, wie nützlich es ist, zwischen "Du hast es vermasselt" und "Ich habe es vermasselt" zu unterscheiden. Außerdem wird angezeigt, wie der statische Status (man könnte sagen "Java-Anwendung" oder "Java-Umgebung") für ISEs immer noch als Status zählt.
Andrew McNamee
@ AndrewMcNamee Ich denke, das AssertionErrorwäre besser geeignet für Fälle, in denen ich weiß, dass ich es vermasselt habe. Es scheint InternalErrornur deshalb so zu sein, weil es sich eher im JDK-Code als im Anwendungscode befindet - eine zweifelhafte Unterscheidung.
Ramon
Ja, da 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 oft in dem defaultFall für switches. IMO InternalErrordient immer noch einem nützlichen Zweck; Die Person, die den Stack-Trace liest, weiß, dass sie "Whoa, das JDK hat es vermasselt" annehmen kann, aber die JDK-Autoren hätten es wahrscheinlich weglassen können.
Andrew McNamee
2

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

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent etc.

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

Ich denke, beide bedeuten gleich, aber unterschiedliche Formulierungen.

Amit Deshpande
quelle
1

Bei einer Bibliothek, soll es wirft eine IllegalStateExceptionoder , IllegalArgumentExceptionwenn es einen Fehler aufgrund des Benutzercode erkennt, während sollte die Bibliothek einen werfen , AssertionErrorwenn es aufgrund der Bibliothek eigener Implementierung eines Fehler erkennt.

In den Tests der Bibliothek können Sie beispielsweise erwarten, dass die Bibliothek einen löst, IllegalStateExceptionwenn die Reihenfolge der Methodenaufrufe falsch ist. Aber Sie werden nie erwarten, dass die Bibliothek eine wirft AssertionError.

Yang Bo
quelle
0

Hier gibt es keine "Diskrepanz". In Blochs Wortlaut gibt es nichts, was ausschließt, was in der JLS steht. Bloch sagt einfach, wenn Sie Umstand A haben, werfen Sie diese Ausnahme. Er sagt nicht , dass diese Ausnahme nur in diesem Zustand ausgelöst wird / werden sollte . Das JLS sagt, dass diese Ausnahme ausgelöst wird, wenn A, B oder C.

user207421
quelle
Das könnte man wohl sagen. Wenn es andererseits beabsichtigte Verwendungsumstände gegeben hätte, die sich von den von ihm angegebenen Umständen unterschieden, wäre dies 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" verwendet werden sollte, ist dies möglicherweise nicht so informativ. Aber zugegeben, ich glaube, ich spalte hier die Haare;)
Andrew McNamee
@AndrewMcNamee Ich habe sagen , dass. Ich weiß nicht, was der Rest Ihres Kommentars überhaupt bedeutet, aber Sie versuchen, eine Diskrepanz herzustellen, bei der keine existiert. Sie begehen einen logischen Irrtum.
user207421
0

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, IllegalStateExceptionhier anstelle von zu werfen AssertionException, obwohl dies in die Kategorie "Java-Umgebung" fällt.

Antak
quelle