Me topé con un código que se veía así:
void run() {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() {
throw new RuntimeException();
}
Este código me sorprende porque parece que el run()método-es capaz de arrojar un Exception, ya que lo atrapa Exceptiony luego lo vuelve a arrojar, pero no se declara que el método arroje Exceptiony aparentemente no es necesario. Este código se compila muy bien (en Java 11 al menos).
Mi expectativa sería que tendría que declarar throws Exceptionen el run()método-.
Información extra
De manera similar, si doSomethingse declara que se lanza, IOExceptionentonces solo se IOExceptiondebe declarar en el run()método-, aunque Exceptionse atrape y se vuelva a lanzar.
void run() throws IOException {
try {
doSomething();
} catch (Exception ex) {
System.out.println("Error: " + ex);
throw ex;
}
}
void doSomething() throws IOException {
// ... whatever code you may want ...
}
Pregunta
A Java generalmente le gusta la claridad, ¿cuál es la razón detrás de este comportamiento? ¿Siempre ha sido así? ¿Qué en la especificación del lenguaje Java permite que el run()método no necesite declarar throws Exceptionen los fragmentos de código anteriores? (Si quisiera agregarlo, IntelliJ me advierte que Exceptionnunca se tira).

javac: he estado encontrando casos en los que el compilador Eclipse fue más indulgente.-source 1.6bandera genera un error de compilación como se esperaba. Compilar con la compatibilidad fuente 7 no no elevar el error de compilaciónIn detail, in Java SE 7 and later, when you declare one or more exception types in a catch clause, and rethrow the exception handled by this catch block, the compiler verifies that the type of the rethrown exception meets the following conditions : 1. 1. The try block is able to throw it. 2. There are no other preceding catch blocks that can handle it. 3. It is a subtype or supertype of one of the catch clause's exception parameters.Respuestas:
No he escaneado las
JLSpreguntas que ha hecho en su pregunta, así que tome esta respuesta con un grano de sal. Quería hacer un comentario, pero habría sido demasiado grande.A veces me parece gracioso, cómo
javaces bastante "inteligente" en algunos casos (como en su caso), pero deja muchas otras cosas para ser manejadas más adelanteJIT. En este caso, es solo que el compilador "puede decir" que soloRuntimeExceptionse capturaría un. Esto es obvio, es lo único que arrojasdoSomething. Si cambia ligeramente su código a:verá un comportamiento diferente, porque ahora
javacpuede decir que hay una nuevaExceptionque está lanzando, no relacionada con la que atrapó.Pero las cosas están lejos de ser ideales, puede "engañar" al compilador una vez más a través de:
OMI, por
ex2 = ex;eso no debería fallar nuevamente, pero lo hace.Por si acaso esto fue compilado con
javac 13+33fuente
ex2lanzará la excepción, se creó originalmente como unExceptionpero luego se le reasigna yex, por lo tanto, el compilador no puede ser inteligente.JLSpodría venir y proporcionar las citas necesarias para probar esto; desafortunadamente no los tengo.ex = ex;), la heurística ya no se aplica. Este comportamiento parece aplicarse a todos los niveles de origen del 7 al 11 y probablemente del 13