Error de comstackdor de bloque de catch inalcanzable de Java

¿Por qué en Java podemos atrapar una Exception incluso si no se lanza, pero no podemos detectar su subclase (excepto para las excepciones de RuntimeException “no comprobadas” y sus subclases). Código de ejemplo:

 class Test { public static void main(String[] args) { try { // do nothing } catch (Exception e) { // OK } try { // do nothing } catch (IOException e) { // COMPILER ERROR: Unreachable catch block for IOException. //This exception is never thrown from the try statement body } } } 

¿Algunas ideas?

Una RuntimeException podría ser arrojada por cualquier código. En otras palabras, el comstackdor no puede predecir fácilmente qué tipo de código puede arrojarlo. Una RuntimeException puede ser atrapada por un bloque catch(Exception e) .

IOException , sin embargo, es una excepción comprobada: solo las llamadas a métodos declaradas para lanzarlo pueden hacerlo. El comstackdor puede estar (razonablemente) seguro de que no puede ocurrir a menos que existan llamadas a métodos que se declaren para lanzarlo.

El comstackdor de Java simplemente no tiene en cuenta la situación de “no hay ningún código en el bloque de prueba”; siempre le permite capturar excepciones no verificadas, ya que en todos los escenarios razonables habrá código que podría arrojar una excepción no verificada.

De la sección 14.21 del JLS:

Un bloque catch C es alcanzable si ambos de los siguientes son verdaderos:

  • Se puede alcanzar alguna expresión o instrucción throw en el bloque try y se puede lanzar una excepción cuyo tipo sea asignable al parámetro de la cláusula catch C (una expresión se considera alcanzable si se puede alcanzar la instrucción más interna que la contiene).
  • No hay un bloque de captura anterior A en la instrucción try de modo que el tipo de parámetro de C sea el mismo o una subclase del tipo del parámetro de A.

Podría decirse que el comstackdor debería darse cuenta de que no hay expresiones dentro del bloque try en su primer caso … parece que para mí todavía es una cláusula catch inaccesible.

EDITAR: Como se menciona en los comentarios, la sección 14.20 contiene esto:

Se trata de un error en tiempo de comstackción si una cláusula de captura detecta el tipo de excepción comprobada E1, pero no existe ningún tipo de excepción comprobada E2 , por lo que se cumple lo siguiente:

  • E2 <: E1
  • El bloque try correspondiente a la cláusula catch puede arrojar E2
  • Ningún bloque de catch precedente de la instrucción try que encierra inmediatamente atrapa E2 o un supertipo de E2 .

a menos que E1 sea ​​la clase Excepción.

Así que parece que eso es lo que realmente estás cometiendo , pero la especificación no es tan clara como podría ser en términos de bloques de captura inalcanzables en 14.21.

Las excepciones IO solo se pueden capturar si el comstackdor predice que puede haber algo en el código que arroje IOException. Entonces recibes una advertencia de que la excepción IO nunca se lanza desde el cuerpo de la statement try (ya que no hay nada en el cuerpo de la prueba).

No puede atrapar excepciones comprobadas no derribadas porque no pueden lanzarse. Puede capturar Exception porque una excepción de tiempo de ejecución no verificada ES una Exception y PODRÍA ser lanzada.

Porque para las excepciones comprobadas, el método que las arroja debe declarar explícitamente este hecho mediante la palabra clave ‘throws’, por lo tanto, si un bloque no tiene ‘throws IOException’ en su caso, el comstackdor tiene la información que es imposible para una IOException ser arrojado, por lo que lo que sea que hagas después de atraparlo, sería inalcanzable.

IOException es una Excepción comprobada que solo es lanzada por un código relacionado con IO. Como tu bloque try no hace nada, nada relacionado con IO ocurrirá nunca, IOExceptions nunca será lanzado, por lo que no hay forma de que el bloque catch sea ejecutado y el comstackdor no te permite moverte con él. Como dijo, Exception puede referirse a excepciones de tiempo de ejecución no comprobadas que pueden ocurrir en cualquier momento. Esa es la principal diferencia entre las excepciones no comprobadas y comprobadas, y es por eso que el comstackdor no aplica el código para detectar todas las posibles excepciones de tiempo de ejecución.

Simplemente Java asume que cualquier línea de código puede arrojar una Exception genérica o Throwable , es decir. OutOfMemoryException que es un Error más bien una Exception . Lo mismo aplica para NPE.

IOException es una excepción específica que solo puede ser lanzada por código administrado, por lo que si no tiene llamadas de E / S en su captura bloquee su comstackdor que no hay posibilidad de atraparlo.

Solo para compararlo con C # world, en C # se comstackrá ese código, pero sería un error conceptual ya que si no haces nada, no llegas al bloque catch. Una herramienta como ReSharper puede advertirte sobre eso.