tipos - todas las excepciones en java
Cómo ajustar las excepciones comprobadas pero mantener las excepciones de tiempo de ejecución originales en Java (7)
El problema es que la Exception
es demasiado amplia. Debe saber exactamente cuáles son las posibles excepciones comprobadas.
try {
// code that throws checked and unchecked exceptions
} catch (IOException | SomeOtherException ex) {
throw new RuntimeException(ex);
}
Las razones por las que esto no funcionaría revelan problemas más profundos que deberían abordarse en su lugar:
Si un método declara que throws Exception
entonces es demasiado amplio. Saber que "algo puede salir mal" sin más información no sirve para el llamante. El método debe usar clases de excepción específicas en una jerarquía significativa, o usar excepciones no verificadas si es apropiado.
Si un método arroja demasiados tipos diferentes de excepciones verificadas, entonces es demasiado complicado. Debe ser refactorizado en múltiples métodos más simples, o las excepciones deben organizarse en una jerarquía de herencia sensible, dependiendo de la situación.
Por supuesto que puede haber excepciones a la regla. La declaración de un método throws Exception
puede ser perfectamente razonable si es consumido por algún tipo de marco transversal (como JUnit o AspectJ o Spring) en lugar de incluir una API para que otros la utilicen.
Tengo algún código que podría arrojar excepciones comprobadas y en tiempo de ejecución.
Me gustaría capturar la excepción marcada y envolverla con una excepción de tiempo de ejecución. Pero si se lanza una excepción RuntimeException, no tengo que envolverla porque ya es una excepción en tiempo de ejecución.
La solución que tengo tiene un poco de sobrecarga y no es "neat":
try {
// some code that can throw both checked and runtime exception
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
¿Alguna idea para una forma más elegante?
Generalmente, utilizo el mismo tipo de estructura de código, pero lo condensé en una de las pocas veces en que un operador ternario hace que el código sea mejor:
try {
// code that can throw
}
catch (Exception e) {
throw (e instanceof RuntimeException) ? (RuntimeException) e : new RuntimeException(e);
}
Esto no requiere métodos adicionales o bloques de catch
, por lo que me gusta.
Puedes reescribir lo mismo usando el operador instanceof
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
if (e instanceof RuntimeException) {
throw e;
} else {
throw new RuntimeException(e);
}
}
Sin embargo, su solución se ve mejor.
Realmente no.
Si haces esto mucho, podrías meterlo en un método auxiliar.
static RuntimeException unchecked(Throwable t){
if (t instanceof RuntimeException){
return (RuntimeException) t;
} else if (t instanceof Error) { // if you don''t want to wrap those
throw (Error) t;
} else {
return new RuntimeException(t);
}
}
try{
// ..
}
catch (Exception e){
throw unchecked(e);
}
Tengo un archivo .class especialmente compilado que contiene lo siguiente:
public class Thrower {
public static void Throw(java.lang.Throwable t) {
throw t;
}
}
Simplemente funciona. El compilador de java normalmente se negaría a compilar esto, pero al verificador de bytecode no le importa en absoluto.
La clase se usa de manera similar a la respuesta de Peter Lawrey:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
Thrower.Throw(e);
}
Uso un relanzamiento "ciego" para pasar las excepciones verificadas. He usado esto para pasar a través de la API de Streams donde no puedo usar lambdas que arrojan excepciones comprobadas. por ejemplo, tenemos interfaces funcionales ThrowingXxxxx para que la excepción verificada se pueda pasar.
Esto me permite detectar la excepción marcada en una persona que llama, naturalmente, sin necesidad de saber que la persona que llamó tuvo que pasarla a través de una interfaz que no permitía las excepciones comprobadas.
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw rethrow(e);
}
En un método de llamada puedo declarar la excepción verificada de nuevo.
public void loadFile(String file) throws IOException {
// call method with rethrow
}
/**
* Cast a CheckedException as an unchecked one.
*
* @param throwable to cast
* @param <T> the type of the Throwable
* @return this method will never return a Throwable instance, it will just throw it.
* @throws T the throwable as an unchecked throwable
*/
@SuppressWarnings("unchecked")
public static <T extends Throwable> RuntimeException rethrow(Throwable throwable) throws T {
throw (T) throwable; // rely on vacuous cast
}
Hay muchas opciones diferentes para manejar las excepciones. Usamos algunos de ellos.
https://vanilla-java.github.io/2016/06/21/Reviewing-Exception-Handling.html
Throwables.propagate()
Guava hace exactamente esto:
try {
// some code that can throw both checked and runtime exception
} catch (Exception e) {
throw Throwables.propagate(e);
}
ACTUALIZACIÓN: Este método ahora está en desuso. Vea esta página para una explicación detallada.