2012-10-02 14 views
63

Questo è venuto in una discussione con un collega oggi.Qual è l'uso previsto di IllegalStateException?

Il Javadocs per lo stato di Java IllegalStateException che:

segnali che un metodo è stato invocato in un momento illegale o inappropriato. In altre parole, l'ambiente Java o l'applicazione Java non sono nello stato appropriato per l'operazione richiesta.

E Effective Java dice (Articolo 60, pag 248):

Un'altra eccezione comunemente riutilizzato è IllegalStateException. Questa è generalmente l'eccezione da lanciare se l'invocazione è illegale a causa dello stato dell'oggetto ricevente. Ad esempio, questa sarebbe l'eccezione da lanciare se il chiamante ha tentato di utilizzare qualche oggetto prima che fosse inizializzato correttamente.

Sembra che ci sia un po 'di discrepanza qui. La seconda frase dei javadoc fa sembrare che l'eccezione possa descrivere una condizione molto ampia dello stato di esecuzione di Java, ma la descrizione in Java efficace lo fa sembrare come se fosse usato per condizioni legate specificamente allo stato dello stato di cui il metodo è stato chiamato.

Gli usi che ho visto nel JDK (ad es. Collezioni, Matcher) e in Guava sembrano sicuramente rientrare nella categoria di cui parla Java efficace ("Questo oggetto è in uno stato in cui questo metodo non può essere chiamato "). Anche questo sembra coerente con il fratello IllegalStateExceptionIllegalArgumentException.

Esistono alcuni legittimi usi di IllegalStateException nel JDK che si riferiscono all'ambiente "Java" o "Applicazione Java"? Oppure le guide delle migliori pratiche sostengono di usarlo per lo stato di esecuzione più ampio? Altrimenti, perché diamine sono i javadoc così formulati? ;)

+4

Su una nota forse non correlata, ho notato che il tag [illegalstatexception] di StackOverflow dice "In Java, un'eccezione che si verifica quando si utilizzano più thread, per cui un thread modifica un oggetto in un modo che lo rende incompatibile con l'uso di quell'oggetto nel secondo thread, ponendo l'oggetto in uno stato illegale. Eh? Da dove viene questo? –

+3

"L'applicazione Java" è quella che scrivi e puoi usare 'IllegalStateException' lì (direttamente o perché stai usando Guava, per esempio). Dov'è la discrepanza? –

+4

Il tag wiki sembra fasullo, ho inviato una modifica prendendo a prestito liberamente da questa domanda; dovresti vedere la nuova versione una volta passata la peer review. – meriton

risposta

35

Ecco un uso particolarmente legittima di questa eccezione nel JDK (vedi: URLConnection.setIfModifiedSince(long) tra 300 + altri usi di esso:

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

Credo che l'esempio è abbastanza chiaro se l'oggetto è in particolare. stato ("già collegata"), alcune operazioni non dovrebbero essere chiamati. In questo caso, quando è stata stabilita la connessione, alcune proprietà non può essere impostato.

questa eccezione è particolarmente utile quando la classe ha un certo stato (macchina a stati?) che cambia nel tempo, rendendo alcuni metodi irrilevanti o impossibile. Pensa a una classe Car con metodi start(), stop() e fuel(). Mentre chiamare lo start() due volte, uno dopo l'altro, probabilmente non è niente di sbagliato, ma alimentare una macchina avviata è certamente una cattiva idea. Vale a dire - l'auto è in uno stato sbagliato.

Probabilmente API buona non dovrebbe consentirci di chiamare metodi in uno stato errato, in modo che problemi simili vengano scoperti in fase di compilazione, non in fase di runtime. In questo particolare esempio, la connessione a un URL dovrebbe restituire un oggetto diverso con un sottoinsieme di metodi, che sono tutti validi dopo la connessione.

+1

Sono d'accordo con la tua risposta. Ma questo non spiega perché Effectiva Java e Guava utilizza questa eccezione come un '' IllegalArgumentException'' – Zarathustra

0

Suppongo che se vedete l'utilizzo di IllegalStateException direi secondo se più appropriato.Questa eccezione è utilizzato in molti pacchetti

  • Java.net
  • java.nio
  • java.util
  • java.util.concurrrent ecc

Per specificare un esempio ArrayBlockingQueue.add tiri questa eccezione se la coda è già piena. Ora pieno è lo stato dell'oggetto e viene invocato in caso di tempo non appropriato o illegale

Suppongo che entrambi significano lo stesso, ma una differenza di testo.

4

Ecco un esempio nel JDK. Esiste una classe privata del pacchetto chiamata java.lang.Shutdown. Se il sistema si sta spegnendo e si tenta di aggiungere un nuovo hook, viene generata la IllegalStateException. Si potrebbe sostenere che questo soddisfa i criteri della guida "javadoc" - dal momento che è l'ambiente Java che si trova nello stato sbagliato.

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

Tuttavia illustra anche che non c'è davvero alcuna distinzione tra la guida "Javadoc" e la guida "Effective Java". A causa del modo in cui viene implementato Shutdown, l'arresto della JVM viene memorizzato in un campo chiamato stato. Pertanto soddisfa anche la guida "Java efficace" per quando utilizzare IllegalStateException, poiché il campo "stato" fa parte dello stato dell'oggetto destinatario. Poiché l'oggetto ricevente (Shutdown) si trova nello stato sbagliato, genera l'IllegalStateException.

A mio parere le due descrizioni di quando utilizzare IllegalStateException sono coerenti. La descrizione di Java efficace è un po 'più pratica, tutto qui. Per la maggior parte di noi, la parte più importante dell'intero ambiente Java è la classe che stiamo scrivendo in questo momento, quindi questo è ciò su cui l'autore si sta concentrando.

+1

Ah, mi piace questo esempio! L'errore "InternalError" appena sotto l'ISE dimostra anche quanto sia utile fare una distinzione "You incasinato" rispetto a "I incasinato". Inoltre, mostra come lo stato statico (si potrebbe dire lo stato "Applicazione Java" o "Ambiente Java") conti ancora come stato per quanto riguarda gli ISE. –

+0

@AndrewMcNamee Penso che "AssertionError" sarebbe più appropriato per i casi in cui so che ho incasinato. Sembra un "InternalError" solo perché è all'interno del codice JDK piuttosto che nel codice dell'applicazione - una distinzione dubbia. – Ramon

+0

Sì, sono assolutamente d'accordo su "AssertionError"; sembra trasmettere "ho incasinato" in contrasto con "Hai incasinato" (che ISE implica). Lo uso molto nel caso di 'default' per' switch'es. IMO 'InternalError' serve ancora a uno scopo utile; la persona che legge la traccia dello stack sa che può assumere "Whoa, il JDK incasinato", ma probabilmente gli autori di JDK avrebbero potuto lasciarlo fuori. –

0

Non c'è "discrepanza" qui. Non c'è nulla nella formulazione di Bloch che escluda ciò che dice nel JLS. Bloch sta semplicemente dicendo che se hai la circostanza A, lancia questa eccezione. Lui è non dicendo che questa eccezione è/dovrebbe essere generata solo in questa condizione. Il JLS sta dicendo questa viene generata un'eccezione se A, B o C.

+0

Suppongo che tu possa dirlo. D'altra parte, se avesse previsto circostanze d'uso diverse dalla circostanza che ha dato, allora la cosa potrebbe non essere così significativa in quanto sarebbe meno specifica. In altre parole, se l'ISE fosse destinato ad essere utilizzato in altre circostanze rispetto all'attuale "Hai chiamato questo metodo su di me, ma non sono in uno stato in cui posso fare questo" caso, potrebbe non essere così informativo. Ma ammettiamolo, penso che sto spaccando i capelli qui;) –

+0

@AndrewMcNamee I * l'ho fatto *. Non so cosa significhi il resto del tuo commento, ma stai cercando di creare una discrepanza in cui non esiste nessuno. Stai commettendo un errore logico. – EJP

0

mi sono imbattuto in questo con:

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

penso che sarà impraticabile per me gettare IllegalStateException qui al posto di AssertionException anche anche se questo rientra nella categoria "l'ambiente Java".

0

Data una biblioteca, si deve lanciare un IllegalStateException o IllegalArgumentException ogni volta che rileva un bug a causa del codice utente, mentre la biblioteca dovrebbe lanciare un AssertionError ogni volta che rileva un bug dovuto alla propria implementazione della biblioteca.

Ad esempio, nei test della libreria, è possibile che la libreria lanci uno IllegalStateException quando l'ordine delle chiamate al metodo è errato. Ma non ti aspetteresti mai che la biblioteca lanci un AssertionError.

Problemi correlati