Relanzar excepciones en Java sin perder el seguimiento de la pila

417

En C #, puedo usar la throw;instrucción para volver a generar una excepción mientras se conserva el seguimiento de la pila:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

¿Hay algo como esto en Java ( que no pierde el rastro original de la pila )?

ripper234
fuente
44
¿Por qué crees que pierde el stacktrace original? La única forma de perderlo cuando lanzas una nueva SomeOtherException y olvidas asignar la causa raíz en el constructor o en initCause ().
akarnokd
44
Creo que así es como se comporta el código en .Net, pero ya no soy positivo. Puede valer la pena buscarlo en alguna parte o realizar una pequeña prueba.
ripper234
11
Throwables no se modifican arrojándolos. Para actualizar el seguimiento de la pila, debe llamar fillInStackTrace(). Convenientemente, este método se llama en el constructor de a Throwable.
Robert
50
En C #, sí, throw e;perderá el stacktrace. Pero no en Java.
Tim Goodman
Algunos documentos de Oracle sobre excepciones con Java 7: capturar múltiples tipos de excepción y volver a lanzar excepciones con una verificación de tipo mejorada
Guillaume Husta

Respuestas:

560
catch (WhateverException e) {
    throw e;
}

simplemente volverá a lanzar la excepción que ha detectado (obviamente, el método circundante debe permitir esto a través de su firma, etc.) La excepción mantendrá el seguimiento de la pila original.

Brian Agnew
fuente
44
Hola, InterruptedException e emite un mensaje de excepción no controlado cuando agrego la línea throw e. No es así si lo reemplazo con la excepción más amplia e. ¿Cómo debe hacerse esto correctamente?
James P.
1
@ James, acabo de observar que el mensaje desaparece si se agrega "throws XxxException" en la declaración de la función.
Shiouming
2
En Java 7, el compilador para este replanteamiento es más inteligente. Ahora funciona bien con excepciones específicas de "lanzamiento" en el método de contención.
Waldemar Wosiński
193
@James Si catch(Exception e) { throw e; }eso no se manejará. Si usted catch(InterruptedException ie) { throw ie; }será manejado. Como regla general, no lo hagas, ¡ catch(Exception e)esto no es pokemon, y no queremos atraparlos a todos!
corsiKa
3
@corsiKa No es necesariamente cierto que no quieras "Atraparlos a todos", es solo un caso de uso diferente. Si tiene un bucle de nivel superior o un controlador de eventos (por ejemplo, dentro de la ejecución de un hilo) si no captura al menos RuntimeException y lo registra, a menudo perderá la excepción por completo Y saldrá silenciosamente de un bucle importante para qué A menudo es un fracaso de una sola vez. También es realmente bueno para la funcionalidad de complementos donde no sabes qué código adicional podría hacer o tirar ... Para usos de arriba hacia abajo como estos La excepción de captura a menudo no solo es una buena idea, sino una práctica recomendada.
Bill K
82

Yo preferiría:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}
Markus Lausberg
fuente
66
Definitivamente apropiado en Java para capturar excepciones específicas que genéricas y, por ejemplo, verificar. +1
amischiefr
8
-1 porque nunca deberías atrapar la "Excepción" a menos que sepas lo que estás haciendo.
Stroboskop
19
@Stroboskop: cierto, ¡pero para responder es mejor usar el mismo código (similar) que en la pregunta!
user85421
14
A veces, capturar todas las excepciones está bien. Como cuando estás escribiendo un caso de prueba. O para fines de registro. O, en general, donde no atrapar significa estrellarse.
John Henckel
1
@ JohnHenckel y otros: puntos válidos añadidos. Actualicé la pregunta para dejar en claro que la captura Exceptionno suele ser lo correcto, en la mayoría de los casos (pero no en todos).
Por Lundberg
74

También puede envolver la excepción en otro Y mantener el seguimiento de la pila original pasando la Excepción como Throwable como parámetro de causa:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}
Olvagor
fuente
8
También recomendaría agregar un mensaje junto, usandothrow new YourOwnException("Error while trying to ....", e);
Julien
esto es lo que estaba buscando, especialmente la versión del primer comentario donde puedes pasar tu propio mensaje
Csaba
Esto muestra el mensaje de error correctamente, pero el seguimiento de la pila muestra la línea de error como una línea con "lanzar nuevo ....... (e)", no la línea original que causó la excepción.
Ashburn RK
22

En Java es casi lo mismo:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}
alves
fuente
55
No, siempre y cuando no cree una instancia de un nuevo objeto Exception, el stacktrace permanece igual.
Mnementh
28
Agregaría una captura específica para FooException
dfa
3
En este caso específico, estoy de acuerdo, pero agregar una captura específica puede no ser la opción correcta: imagine que tiene un código común para todas las excepciones y luego, para una excepción en particular, vuelva a lanzarlo.
alves
1
@MarkusLausberg Pero finalmente no hay excepciones.
Robert
Sí, pero esta no era la pregunta.
Markus Lausberg
14

En Java, que acaba de lanzar la excepción que pillan, por lo que throw een lugar de sólo throw. Java mantiene el seguimiento de la pila.

David M
fuente
6

algo como esto

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
fuente
5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Este es un ejemplo concreto donde el método arroja un IOException. Los finalmedios tsolo pueden contener una excepción lanzada desde el bloque try. Material de lectura adicional se puede encontrar aquí y aquí .

Daniel
fuente
1
No tiene que ser final. Ver docs.oracle.com/javase/7/docs/technotes/guides/language/… y stackoverflow.com/a/6889301/131160
jcsahnwaldt dice GoFundMonica el
3

El seguimiento de pila se conserva si ajusta la excedencia capturada en otra excepción (para proporcionar más información) o si simplemente vuelve a lanzar la excedencia atrapada.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }

Sindre
fuente
2

Estaba teniendo una situación similar en la que mi código potencialmente arroja una serie de excepciones diferentes que solo quería volver a lanzar. La solución descrita anteriormente no funcionaba para mí, porque Eclipse me dijo que eso throw e;lleva a una excepción sin control, así que acabo de hacer esto:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Trabajó para mi....:)

Matías
fuente