java - try - ¿Por qué se marcan las excepciones controladas permitidas para el código que no arroja excepciones?




try catch throw java (2)

Citando la Especificación del Lenguaje Java, §11.2.3 :

Es un error en tiempo de compilación si una cláusula de captura puede detectar la clase de excepción comprobada E1 y no es el caso que el bloque try correspondiente a la cláusula catch pueda arrojar una clase de excepción comprobada que sea una subclase o superclase de E1, a menos que E1 Excepción o una superclase de Excepción.

Supongo que esta regla se originó mucho antes que Java 7, donde las capturas múltiples no existían. Por lo tanto, si tuviera un bloque try que arrojara una multitud de excepciones, la forma más fácil de capturar todo sería capturar una superclase común (en el peor de los casos, Exception o Throwable si también quiere detectar Error s).

Tenga en cuenta que es posible que no capte un tipo de excepción que no esté relacionado con lo que se arroja realmente: en su ejemplo, capturar cualquier subclase de Throwable que no sea una RuntimeException será un error:

try {
    System.out.println("hello");
} catch (IOException e) {  // compilation error
    e.printStackTrace();
}

Editar por OP: la parte principal de la respuesta es el hecho de que los ejemplos de preguntas funcionan solo para la clase Excepción. Generalmente no se permite capturar excepciones comprobadas en lugares aleatorios del código. Perdón si confundí a alguien usando estos ejemplos.

https://code.i-harness.com

En Java, los métodos que lanzan excepciones controladas ( Exception o sus subtipos - IOException, InterruptedException, etc.) deben declarar throws statement:

public abstract int read() throws IOException;

Los métodos que no declaran arrojar declaración no pueden arrojar excepciones marcadas.

public int read() { // does not compile
    throw new IOException();
}
// Error: unreported exception java.io.IOException; must be caught or declared to be thrown

Pero detectar excepciones comprobadas en métodos seguros sigue siendo legal en Java:

public void safeMethod() { System.out.println("I'm safe"); }

public void test() { // method guarantees not to throw checked exceptions
    try {
        safeMethod();
    } catch (Exception e) { // catching checked exception java.lang.Exception
        throw e; // so I can throw... a checked Exception?
    }
}

En realidad no. Es un poco divertido: el compilador sabe que e no es una excepción comprobada y permite volver a lanzarlo. Las cosas son incluso un poco ridículas, este código no se compila:

public void test() { // guarantees not to throw checked exceptions
    try {
        safeMethod();
    } catch (Exception e) {        
        throw (Exception) e; // seriously?
    }
}
// Error: unreported exception java.lang.Exception; must be caught or declared to be thrown

El primer fragmento fue una motivación para una pregunta.

El compilador sabe que las excepciones comprobadas no pueden arrojarse dentro de un método seguro, por lo que tal vez debería permitir capturar solo las excepciones no verificadas.

Volviendo a la pregunta principal , ¿hay alguna razón para implementar la captura de excepciones marcadas de esta manera? ¿Es solo un defecto en el diseño o me faltan algunos factores importantes, tal vez incompatibilidades hacia atrás? ¿Qué podría salir mal si solo RuntimeException fuera atrapada en este escenario? Los ejemplos son muy apreciados.


El problema aquí es que las limitaciones de las excepciones controladas / no comprobadas afectan a lo que su código puede arrojar , no a lo que está permitido atrapar . Si bien aún puede atrapar cualquier tipo de Exception , las únicas que puede arrojar de nuevo son las que no se marcaron. (Esta es la razón por la que convertir su excepción no verificada en una excepción marcada rompe su código).

Capturar una excepción sin marcar con Exception es válida, porque las excepciones sin marcar (también conocidas como RuntimeException s) son una subclase de Exception, y sigue las reglas de polimorfismo estándar; no convierte la excepción capturada en una Exception , del mismo modo que almacenar una String en un Object no convierte la String en un Object . Polimorfismo significa que una variable que puede contener un Object puede contener cualquier cosa derivada de un Object (como una String ). Del mismo modo, como Exception es la superclase de todos los tipos de excepción, una variable de tipo Exception puede contener cualquier clase derivada de Exception , sin convertir el objeto en una Exception . Considera esto:

import java.lang.*;
// ...
public String iReturnAString() { return "Consider this!"; }
// ...
Object o = iReturnAString();

A pesar de que el tipo de variable es Object , o aún almacena una String , ¿no es así? Del mismo modo, en tu código:

try {
    safeMethod();
} catch (Exception e) { // catching checked exception
    throw e; // so I can throw... a checked Exception?
}

Lo que esto significa es en realidad "capturar cualquier cosa compatible con Exception clase (es decir, Exception y todo lo que se derive de ella)". Lógica similar se usa en otros idiomas, también; por ejemplo, en C ++, la captura de std::exception también detectará std::runtime_error , std::logic_error , std::bad_alloc , cualquier excepción creada por el usuario definida correctamente, etc., porque todas derivan de std::exception

tl; dr: no está detectando excepciones controladas , está atrapando excepciones. La excepción solo se convierte en una excepción comprobada si la convierte en un tipo de excepción comprobada.







unchecked-exception