2012-10-02 38 views
63

Esto surgió en una discusión con un colega hoy.¿Cuál es el uso previsto de IllegalStateException?

El Javadocs para el estado de Java IllegalStateException que:

Señales de que un método que se ha invocado en un momento ilegal o inapropiada. En otras palabras, el entorno Java o la aplicación Java no se encuentran en un estado apropiado para la operación solicitada.

Y dice Effective Java (artículo 60, página 248):

Otra excepción es comúnmente reutilizados IllegalStateException. En general, esta es la excepción a throw si la invocación es ilegal debido al estado del objeto receptor. Por ejemplo, esta sería la excepción para tirar si la persona que llama intenta utilizar algún objeto antes de que se haya inicializado correctamente.

Parece que hay un poco de discrepancia aquí. La segunda oración de los javadocs hace que parezca que la excepción podría describir una condición muy amplia sobre el estado de ejecución de Java, pero la descripción en Java efectivo hace que suene como si se usara para condiciones relacionadas específicamente con el estado del objeto cuyo método ha sido llamado.

Los usos que he visto en el JDK (por ejemplo, colecciones, Matcher) y en Guava definitivamente parecen pertenecer a la categoría sobre la que habla Effective Java ("Este objeto está en un estado donde no se puede llamar este método "). Esto también parece consistente con IllegalStateException 's hermano IllegalArgumentException.

¿Existen usos legítimos de IllegalStateException en el JDK que se relacionen con el "entorno Java" o la "aplicación Java"? ¿O alguna guía de mejores prácticas recomienda usarla para un estado de ejecución más amplio? Si no, ¿por qué demonios son los javadocs redactados así? ;)

+4

En una nota tal vez no relacionada, noté que la etiqueta [illegalstatexception] de StackOverflow dice 'En Java, una excepción que ocurre cuando se usan múltiples hilos, por lo que un hilo modifica un objeto de una manera incompatible con el uso de ese objeto en el segundo hilo, poniendo el objeto en un estado ilegal. ¿Huh? ¿De donde viene esto? –

+3

La "aplicación Java" es la que usted escribe, y puede usar 'IllegalStateException' allí (ya sea directamente o porque está usando Guava, por ejemplo). ¿Dónde está la discrepancia? –

+4

La etiqueta wiki parece falsa, he enviado una edición al tomar prestado generosamente de esta pregunta; Debería ver la nueva versión una vez que haya pasado la revisión por pares. – meriton

Respuesta

35

Aquí está uno su uso es muy legítimo de esta excepción en el JDK (ver: URLConnection.setIfModifiedSince(long) entre más de 300 otros usos de la misma:

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

Creo que el ejemplo es bastante claro Si el objeto está en particular. estado ("ya conectados"), algunas operaciones no deben ser llamados. En este caso, cuando se establece la conexión, algunas propiedades no se puede ajustar.

esta excepción es especialmente útil cuando su clase tiene algún estado (máquina de estado?) que cambia con el tiempo, haciendo que algunos métodos sean irrelevantes t o imposible. Piense en una clase Car que tiene los métodos start(), stop() y fuel(). Si llama al start() dos veces, una después de otra, probablemente no sea nada incorrecto, pero alimentar un automóvil arrancado es ciertamente una mala idea. A saber, el automóvil está en un estado equivocado.

Podría decirse que una buena API no debería permitirnos llamar a los métodos en estado incorrecto para que los problemas como ese se descubran en tiempo de compilación, no en tiempo de ejecución. En este ejemplo particular, la conexión a una URL debe devolver un objeto diferente con un subconjunto de métodos, todos los cuales son válidos después de la conexión.

+1

Estoy de acuerdo con su respuesta. Pero esto no explica por qué Effectiva Java y Guava usan esta Excepción como una '' IllegalArgumentException'' – Zarathustra

0

Supongo que si ves el uso de IllegalStateException diría que es el segundo si es más apropiado.Esta excepción se utiliza en gran cantidad de paquetes

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

Para especificar un ejemplo ArrayBlockingQueue.add tiros esta excepción si la cola ya está llena. Ahora lleno es el estado del objeto y se invoca en el momento inadecuado o ilegal.

Supongo que ambos significan lo mismo, pero la diferencia de redacción.

4

Aquí hay un ejemplo en el JDK. Hay una clase privada de paquete llamada java.lang.Shutdown. Si el sistema se está cerrando e intenta agregar un nuevo enlace, arroja la IllegalStateException. Se podría argumentar que esto cumple con los criterios de la guía "javadoc", ya que es el entorno de Java el que está en el estado incorrecto.

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

Sin embargo, también ilustra que en realidad no hay distinción entre la orientación "javadoc" y la guía "Effective Java". Debido a la forma en que se implementa Shutdown, el apagado de la JVM se almacena en un campo llamado estado. Por lo tanto, también cumple con la guía "Effective Java" para cuándo usar IllegalStateException, ya que el campo "state" es parte del estado del objeto receptor. Dado que el objeto de recepción (Apagado) está en el estado incorrecto, arroja la IllegalStateException.

En mi opinión, las dos descripciones de cuándo usar IllegalStateException son consistentes. La descripción de Effective Java es un poco más práctica, eso es todo. Para la mayoría de nosotros, la parte más importante de todo el entorno de Java es la clase que estamos escribiendo en este momento, por lo que el autor se está centrando en eso.

+1

¡Ah, me gusta este ejemplo! El lanzamiento de 'InternalError' justo debajo del ISE también demuestra lo útil que es hacer una distinción entre" En mal estado "y" En mal estado ". Además, muestra cómo el estado estático (se podría decir "Aplicación Java" o estado "Entorno Java") todavía cuenta como estado en lo que respecta a ISE. –

+0

@AndrewMcNamee Creo que 'AssertionError' sería más apropiado para los casos en que sé que cometí un error. Parece ser un 'InternalError' solo porque está dentro del código JDK en lugar del código de la aplicación, una distinción dudosa. – Ramon

+0

Sí, definitivamente estoy de acuerdo con 'AssertionError'; parece transmitir "I messed up" en lugar de "You messed up" (que ISE implica). Lo uso mucho en el caso 'default' para' switch'es. IMO 'InternalError' todavía sirve para un propósito útil; la persona que lee el rastro de pila sabe que puede suponer "Whoa, el JDK arruinado", pero los autores del JDK probablemente podrían haberlo dejado. –

0

No hay "discrepancias" aquí. No hay nada en la redacción de Bloch que excluya lo que dice en el JLS. Bloch simplemente dice que si tienes la circunstancia A, lanza esta excepción. Él es no diciendo que esta excepción se/debe arrojarse solo en esta condición. El JLS está diciendo esta excepción si A, B, o C.

+0

Supongo que podría decir eso. Pero, por otro lado, si tenía circunstancias de uso intencionadas que eran diferentes de las circunstancias que él dio, entonces el poder podría no ser tan significativo ya que sería menos específico. En otras palabras, si ISE estaba destinado a ser utilizado en otras circunstancias que no sean el caso actual "Me llamaste este método, pero no estoy en un estado en el que pueda hacer eso", podría no ser tan informativo. Pero, reconozco, creo que estoy dividiendo pelos aquí;) –

+0

@AndrewMcNamee I * did * say that. No sé qué significa el resto de tu comentario, pero estás tratando de fabricar una discrepancia donde no existe. Estás cometiendo una falacia lógica. – EJP

0

me encontré con esto con:

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

Creo que va a ser poco práctico para que tire IllegalStateException aquí en lugar de AssertionException incluso aunque esto cae en la categoría de "entorno Java".

0

Dada una biblioteca, debe lanzar una IllegalStateException o IllegalArgumentException cada vez que detecta un error debido al código de usuario, mientras que la biblioteca debe lanzar una AssertionError cada vez que detecta un error debido a la propia implementación de la biblioteca.

Por ejemplo, en las pruebas de la biblioteca, puede esperar que la biblioteca arroje un IllegalStateException cuando el orden de las llamadas al método es incorrecto. Pero nunca esperarás que la biblioteca arroje un AssertionError.

Cuestiones relacionadas