La diferencia entre intentar / atrapar / lanzar e intentar / atrapar (e) / lanzar e

103

Cuál es la diferencia entre

try { }
catch
{ throw; }

y

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

?

¿Y cuándo debo usar uno u otro?

Karim
fuente

Respuestas:

151

Las construcciones

try { ... }
catch () { ... } /* You can even omit the () here */

try { ... }
catch (Exception e) { ... }

son similares en que ambos detectarán todas las excepciones lanzadas dentro del trybloque (y, a menos que simplemente esté usando esto para registrar las excepciones, deben evitarse ). Ahora mira estos:

try { ... }
catch ()
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw;
}

try { ... }
catch (Exception e)
{
    /* ... */
    throw e;
}

El primer y segundo bloque try-catch son EXACTAMENTE lo mismo, simplemente vuelven a lanzar la excepción actual, y esa excepción mantendrá su "fuente" y el seguimiento de la pila.

El tercer bloque try-catch es diferente. Cuando lanza la excepción, cambiará la fuente y el seguimiento de la pila, de modo que parecerá que la excepción ha sido lanzada desde este método, desde esa misma línea throw een el método que contiene ese bloque try-catch.

¿Cual deberías usar? Realmente depende de cada caso.

Digamos que tiene una Personclase con un .Save()método que la conservará en una base de datos. Digamos que su aplicación ejecuta el Person.Save()método en alguna parte. Si su DB se niega a salvar a la Persona, .Save()lanzará una excepción. ¿Deberías usar throwo throw een este caso? Bueno, eso depende.

Lo que prefiero es hacer:

try {
    /* ... */
    person.Save();
}
catch(DBException e) {
    throw new InvalidPersonException(
       "The person has an invalid state and could not be saved!",
       e);
}

Esto debería colocar DBException como la "Excepción interna" de la excepción más nueva que se lanza. Entonces, cuando inspeccione esta InvalidPersonException, el seguimiento de la pila contendrá información del método Save (que podría ser suficiente para que usted resuelva el problema), pero aún tiene acceso a la excepción original si la necesita.

Como comentario final, cuando espere una excepción, realmente debería detectar esa excepción específica, y no una general Exception, es decir, si espera una InvalidPersonException, debería preferir:

try { ... }
catch (InvalidPersonException e) { ... }

a

try { ... }
catch (Exception e) { ... }

¡Buena suerte!

Bruno Reis
fuente
34

El primero conserva el seguimiento de la pila mientras que el segundo lo restablece. Esto significa que si usa el segundo enfoque, el seguimiento de la pila de la excepción siempre comenzará a partir de este método y perderá el seguimiento de la excepción original, lo que podría ser desastroso para alguien que lea los registros de excepciones, ya que nunca descubrirá la causa original de la excepción. .

El segundo enfoque puede ser útil cuando desea agregar información adicional al seguimiento de la pila, pero se usa así:

try
{
    // do something
}
catch (Exception ex)
{
    throw new Exception("Additional information...", ex);
}

Hay un blog posterior discusión de las diferencias.

Darin Dimitrov
fuente
¡Eso es genial para saberlo!
Myles
entonces, ¿por qué usar el segundo entonces? ¿Es mejor usar solo el primero?
Karim
1
El segundo es útil cuando necesita verificar excepciones específicas (se le viene a la mente OutOfRangeException) o necesita registrar el mensaje, etc. El primero parece ser un controlador de excepciones comodín similar a try {} catch (...) {} en c ++.
Salvar el
1
David, eso solo se aplica a la parte de captura (Excepción e) . Y que es independiente de throwfrente throw e.
Henk Holterman
6

Deberías usar

try { }
catch(Exception e)
{ throw }

si desea hacer algo con la excepción antes de volver a lanzarlo (registro, por ejemplo). El lanzamiento solitario conserva el rastro de la pila.

Otávio Décio
fuente
y ¿qué pasará si reemplazo el "lanzamiento" aquí con un "lanzamiento e"?
Karim
5

La diferencia entre una captura sin parámetros y una catch(Exception e)es que obtiene una referencia a la excepción. Desde la versión 2 del marco, las excepciones no administradas se incluyen en una excepción administrada, por lo que la excepción sin parámetros ya no es útil para nada.

La diferencia entre throw;y throw e;es que el primero se usa para volver a generar excepciones y el segundo se usa para lanzar una excepción recién creada. Si usa el segundo para volver a generar una excepción, la tratará como una nueva excepción y reemplazará toda la información de la pila desde donde se lanzó originalmente.

Por lo tanto, no debe utilizar ninguna de las alternativas de la pregunta. No debe usar la captura sin parámetros, y debe usar throw;para volver a generar una excepción.

Además, en la mayoría de los casos, debe usar una clase de excepción más específica que la clase base para todas las excepciones. Solo debe detectar las excepciones que anticipa.

try {
   ...
} catch (IOException e) {
   ...
   throw;
}

Si desea agregar información al volver a generar la excepción, cree una nueva excepción con la excepción original como una excepción interna para conservar toda la información:

try {
   ...
} catch (IOException e) {
   ...
   throw new ApplicationException("Some informative error message", e);
}
Guffa
fuente