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 )?


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

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.


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.
    ...
}

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);
}

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;
}

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.


6

algo como esto

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

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í .



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); }


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....:)

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.