2008-09-22 11 views
33

he visto el siguiente código muchas veces:¿Por qué volver a lanzar excepciones?

try 
{ 
    ... // some code 
} 
catch (Exception ex) 
{ 
    ... // Do something 
    throw new CustomException(ex); 

    // or 
    // throw; 

    // or 
    // throw ex; 
} 

¿Puede usted explicar el propósito de volver a lanzar una excepción? ¿Sigue un patrón/mejores prácticas en el manejo de excepciones? (He leído en alguna parte que se llama patrón "Caller Inform")

Respuesta

38

Retirar la misma excepción es útil si desea, por ejemplo, registrar la excepción, pero no manejarla.

Lanzando una nueva excepción que envuelve la excepción atrapada es buena para la abstracción. Por ejemplo, su biblioteca utiliza una biblioteca de terceros que arroja una excepción que los clientes de su biblioteca no deberían conocer. En ese caso, envuélvalo en un tipo de excepción más nativo de su biblioteca, y arroje eso en su lugar.

+0

¿Entiendo bien, no hay necesidad de manejar una excepción relanzada? – chester89

+4

Lo que quiero decir es esto: si tiene un fragmento de código que no puede tratar con una excepción (es decir, desea que la persona que llama lo maneje), tiene dos opciones: 1. no captarlo; 2. atraparlo, registrarlo en algún lugar, luego volver a lanzarlo. Al volver a tirar, le parece a la persona que llama como si nunca hubiera sido atrapada. –

0

Hasta que comencé a usar EntLib ExceptionBlock, los estaba usando para registrar errores antes de lanzarlos. Algo desagradable cuando piensas que podría haberlos manejado en ese momento, pero en ese momento era mejor hacer que fallaran desafortunadamente en UAT (después de iniciar sesión) en lugar de cubrir un error de flujo.

0

La aplicación probablemente esté capturando esas excepciones repetidas en la parte superior de la pila de llamadas, por lo que volver a lanzarlas permite que el controlador superior las intercepte y procese según corresponda. Es bastante común que la aplicación tenga un controlador de excepción de nivel superior que registra o informa las expectativas.

Otra alternativa es que el codificador fue flojo y en lugar de atrapar solo el conjunto de excepciones que quieren manejar han capturado todo y luego han vuelto a lanzar solo los que realmente no pueden manejar.

1

En general, el "Hacer algo" implica una mejor explicación de la excepción (por ejemplo, envolviéndola en otra excepción) o el rastreo de información a través de una fuente determinada.

Otra posibilidad es si el tipo de excepción no es suficiente información para saber si se debe capturar una excepción, en cuyo caso al capturarla y examinarla se obtendrá más información.

Esto no quiere decir que el método se use por razones puramente buenas, muchas veces se usa cuando un desarrollador piensa que la información de rastreo puede ser necesaria en algún momento futuro, en cuyo caso se obtiene try {} catch {throw;} estilo, que no es útil en absoluto.

1

Creo que depende de lo que intente hacer con la excepción.

Una buena razón sería registrar el error primero en la captura, y luego lanzarlo a la interfaz de usuario para generar un mensaje de error amigable con la opción de ver una vista más "avanzada/detallada" del error, que contiene el error original.

Otro enfoque es un enfoque de "reintento", por ejemplo, se mantiene un recuento de errores, y después de una cierta cantidad de reintentos que es la única vez que el error se envía a la pila (a veces esto se hace para el acceso de base de datos para las llamadas de base de datos ese tiempo de espera, o al acceder a servicios web a través de redes lentas).

Sin embargo, habrá muchas otras razones para hacerlo.

-3

LA PRINCIPAL RAZÓN de volver a lanzar excepciones es dejar la Pila de llamadas intacta, para que pueda obtener una imagen más completa de lo que sucede y la secuencia de llamadas.

8

Por lo general, atrapa y vuelve a lanzar por una de dos razones, dependiendo de dónde se encuentra el código arquitectónicamente dentro de una aplicación.

En el núcleo de una aplicación, normalmente se captura y se vuelve a lanzar para convertir una excepción en algo más significativo. Por ejemplo, si está escribiendo una capa de acceso a datos y está usando códigos de error personalizados con SQL Server, puede traducir SqlException a cosas como ObjectNotFoundException. Esto es útil porque (a) hace que sea más fácil para las personas que llaman manejar tipos específicos de excepción, y (b) porque evita los detalles de implementación de esa capa, como el hecho de que está usando SQL Server para la fuga de persistencia en otras capas, lo cual te permite cambiar las cosas en el futuro más fácilmente.

En los límites de las aplicaciones es común capturar y volver a lanzar sin traducir una excepción para que pueda registrar detalles de la misma, lo que ayuda a la depuración y el diagnóstico de problemas en vivo. Lo ideal es que publique un error en algún lugar que el equipo de operaciones pueda supervisar fácilmente (por ejemplo, el registro de eventos) así como en algún lugar que proporcione contexto en torno a dónde ocurrió la excepción en el flujo de control para desarrolladores (generalmente, rastreo).

24

En realidad no hay una diferencia entre

throw new CustomException(ex); 

y

throw; 

El segundo preservará la información de la pila.

Pero a veces desea hacer que la excepción sea más "amigable" con su dominio de aplicación, en lugar de dejar que DatabaseException llegue a su GUI, levantará su excepción personalizada que contiene la excepción original.

Por ejemplo:

try 
{ 

} 
catch (SqlException ex) 
{ 
    switch (ex.Number) { 
     case 17: 
     case 4060: 
     case 18456: 
      throw new InvalidDatabaseConnectionException("The database does not exists or cannot be reached using the supplied connection settings.", ex); 
     case 547: 
      throw new CouldNotDeleteException("There is a another object still using this object, therefore it cannot be deleted.", ex); 
     default: 
      throw new UnexpectedDatabaseErrorException("There was an unexpected error from the database.", ex); 
    } 
} 
+0

"Su"? ¿La gente realmente no revisa sus mensajes de error? ¡Eso es, como, material erroneo! :-P –

+0

Lo siento: D tienes razón .... (Mi inglés me falló: D) –

+2

Tu primera afirmación es engañosa. throw new CustomException (ex) no hará que pierda la información de la pila, se conservará en la InnerException del objeto CustomException. Es cuando lo haces ex; que la pila está perdida. –

2

puedo pensar en las siguientes razones:

  • Mantener el conjunto de tipos de excepción que se fija, como parte de la API, de modo que las personas que llaman sólo tienen preocuparse por el conjunto fijo de excepciones. En Java, prácticamente está obligado a hacerlo, debido al mecanismo de excepciones comprobadas.

  • Añadiendo algo de información de contexto a la excepción. Por ejemplo, en lugar de dejar pasar el "registro no encontrado" desnudo de la base de datos, es posible que desee atraparlo y agregar "... al procesar la orden no XXX, buscando el producto YYY".

  • Haciendo algo de limpieza: cierre de archivos, invierta transacciones, libere algunos controladores.

10

A veces se desea ocultar los detalles de implementación de un método o mejorar el nivel de abstracción de un problema por lo que es más significativo para la persona que llama de un método. Para hacer esto, puede interceptar la excepción original y sustituir por una excepción personalizada que sea más adecuada para explicar el problema.

Tomemos por ejemplo un método que carga los detalles del usuario solicitado de un archivo de texto. El método supone que existe un archivo de texto con el nombre del ID del usuario y un sufijo de ".data". Cuando ese archivo no existe realmente, no tiene mucho sentido lanzar una excepción FileNotFoundException porque el hecho de que los detalles de cada usuario están almacenados en un archivo de texto es un detalle de implementación interno del método. Entonces, este método podría envolver la excepción original en una excepción personalizada con un mensaje explicativo.

A diferencia del código que se muestra, la práctica recomendada es mantener la excepción original cargándola como la propiedad InnerException de su nueva excepción. Esto significa que un desarrollador aún puede analizar el problema subyacente si es necesario.

Al crear una excepción personalizada, he aquí una lista útil:

• Encontrar un buen nombre que transmite la razón por la excepción fue lanzada y asegúrese de que el nombre termina con la palabra “excepción”.

• Asegúrese de implementar los tres constructores estándar de excepciones.

• Asegúrese de marcar su excepción con el atributo Serializable.

• Asegúrese de implementar el constructor de deserialización.

• Agregue cualquier propiedad de excepción personalizada que pueda ayudar a los desarrolladores a comprender y manejar mejor su excepción.

• Si agrega propiedades personalizadas, asegúrese de implementar y anular GetObjectData para serializar sus propiedades personalizadas.

• Si agrega propiedades personalizadas, anule la propiedad Mensaje para que pueda agregar sus propiedades al mensaje de excepción estándar.

• Recuerde adjuntar la excepción original utilizando la propiedad InnerException de su excepción personalizada.

0

Si nos fijamos en excepciones como en una forma alternativa de obtener un resultado del método, a continuación, volver a lanzar una excepción es como envolver el resultado en algún otro objeto.

Y esta es una operación común en un mundo no excepcional. Por lo general, esto ocurre en un borde de dos capas de aplicación: cuando una función de la capa B llama a una función desde la capa C, transforma el resultado C en el formulario interno B.

A -- calls --> B -- calls --> C

Si no lo hace, a continuación, en la capa de A que llama a la capa de B habrá un conjunto completo de excepciones JDK de manejar. :-)

Como también la respuesta aceptada señala, la capa A puede que ni siquiera tenga conocimiento de la excepción C.

Ejemplo

Capa A, servlet: recupera una imagen y es la meta información
Capa B, biblioteca JPEG: recoge etiquetas DCIM disponibles para analizar un archivo JPEG
Capa C , un DB simple: una clase que lee registros de cadenas de un archivo de acceso aleatorio. Algunos bytes están rotos, por lo que arroja una excepción que dice "no se puede leer la secuencia UTF-8 para grabar 'bibliographicCitation'".

Así que A no entenderá el significado de 'bibliographicCitation'. Por lo tanto, B debe traducir esta excepción para A en TagsReadingException que envuelve el original.

Cuestiones relacionadas