propias - jerarquia de excepciones java
Captura de una excepción que está anidada en otra excepción (7)
Acabo de resolver un problema como este escribiendo un método de utilidad simple, que verificará toda la cadena causada.
/**
* Recursive method to determine whether an Exception passed is, or has a cause, that is a
* subclass or implementation of the Throwable provided.
*
* @param caught The Throwable to check
* @param isOfOrCausedBy The Throwable Class to look for
* @return true if ''caught'' is of type ''isOfOrCausedBy'' or has a cause that this applies to.
*/
private boolean isCausedBy(Throwable caught, Class<? extends Throwable> isOfOrCausedBy) {
if (caught == null) return false;
else if (isOfOrCausedBy.isAssignableFrom(caught.getClass())) return true;
else return isCausedBy(caught.getCause(), isOfOrCausedBy);
}
Cuando lo use, simplemente creará una lista de ifs de la excepción más específica a la menos específica, con una cláusula else de respaldo:
try {
// Code to be executed
} catch (Exception e) {
if (isCausedBy(e, MyException.class)) {
// Handle MyException.class
} else if (isCausedBy(e, AnotherException.class)) {
// Handle AnotherException.class
} else {
throw new IllegalStateException("Error at calling service ''service''");
}
}
Quiero capturar una excepción, que está anidada en otra excepción. Lo estoy haciendo actualmente de esta manera:
} catch (RemoteAccessException e) {
if (e != null && e.getCause() != null && e.getCause().getCause() != null) {
MyException etrp = (MyException) e.getCause().getCause();
...
} else {
throw new IllegalStateException("Error at calling service ''service''");
}
}
¿Hay alguna forma de hacerlo más eficiente y elegante?
Debería agregar algunas comprobaciones para ver si e.getCause().getCause()
es realmente una MyException
. De lo contrario, este código lanzará una ClassCastException
. Probablemente escribiría esto como:
} catch(RemoteAccessException e) {
if(e.getCause() != null && e.getCause().getCause() instanceof MyException) {
MyException ex = (MyException)e.getCause().getCause();
// Do further useful stuff
} else {
throw new IllegalStateException("...");
}
}
Dudo, pero puede verificar con instanceof
si la excepción es del tipo correcto.
Edición: debe haber una razón por la que la excepción anidada esté envuelta, por lo que debe preguntarse cuál es el propósito de capturar la anidada.
El método ExceptionUtils#getRootCause() puede ser muy útil en tales situaciones.
No hay una forma más elegante de "capturar" excepciones anidadas selectivamente. Supongo que si hicieras este tipo de excepción anidada capturando mucho, posiblemente podrías refactorizar el código en un método de utilidad común. Pero tampoco será elegante ni eficiente.
La solución elegante es acabar con la anidación de excepción. No encadene las excepciones en primer lugar, o desenvuelva (selectivamente) y reproduzca las excepciones anidadas más arriba en la pila.
Las excepciones tienden a ser anidadas por 3 razones:
Ha decidido que es poco probable que los detalles de la excepción original sean útiles para la recuperación de errores de la aplicación ... pero desea preservarlos para fines de diagnóstico.
Está implementando métodos de API que no permiten excepciones comprobadas, pero su código (inevitablemente) arroja dichas excepciones. (Una solución común es "contrabandear" la excepción dentro de una excepción no seleccionada).
Está siendo perezoso y está convirtiendo un conjunto diverso de excepciones no relacionadas en una sola excepción para evitar tener muchas excepciones marcadas en su firma de método 1 .
En el primer caso, si ahora necesita discriminar sobre las excepciones envueltas, entonces sus suposiciones iniciales fueron incorrectas. La mejor solución es cambiar las firmas de los métodos para que pueda deshacerse del anidamiento.
En el segundo caso, probablemente debería desenvolver las excepciones tan pronto como el control haya pasado el método de la API problemática.
En el tercer caso, debe reconsiderar su estrategia de manejo de excepciones; es decir, hacerlo correctamente.
1 - De hecho, una de las razones semi-legítimas para hacer esto ha desaparecido debido a la introducción de la sintaxis de captura de múltiples excepciones en Java 7.
No veo ninguna razón por la que desee que el manejo de excepciones sea eficiente y elegante, me conformo con ser efectivo Se llaman excepciones por una razón.
Este código será una pesadilla de mantenimiento. ¿No puedes rediseñar la pila de llamadas para lanzar la excepción que te interesa? Si es importante, las firmas del método deben mostrarlo y no ocultarlo en otras 2 excepciones.
El primero (e! = Null) es innecesario.
Y puede cambiar la tercera mejor para e.getCause (). GetCause () instanceof MyException)
Puedes hacer lo siguiente:
catch (RemoteAccessException e) {
int index = ExceptionUtils.indexOfThrowable(e, MyExcetption.class)
if (index != -1) {
//handleMyException
} else {
}
}