Pregunta

He visto el siguiente código muchas veces:

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

    // or
    // throw;

    // or
    // throw ex;
}

¿Puede explicar el propósito de volver a lanzar una excepción?¿Está siguiendo un patrón/mejor práctica en el manejo de excepciones?(¿Leí en alguna parte que se llama patrón "Información de llamada"?)

¿Fue útil?

Solución

Volver a generar la misma excepción es útil si desea, por ejemplo, registrar la excepción, pero no controlarla.

Lanzar una nueva excepción que envuelva la excepción detectada es bueno para la abstracción.por ejemplo, su biblioteca utiliza una biblioteca de terceros que genera una excepción que los clientes de su biblioteca no deberían conocer.En ese caso, lo envuelve en un tipo de excepción más nativo de su biblioteca y lo lanza en su lugar.

Otros consejos

En realidad hay una diferencia entre

throw new CustomException(ex);

y

throw;

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

Pero a veces desea que la excepción sea más "amigable" para el dominio de su aplicación, en lugar de permitir que la excepción DatabaseException llegue a su GUI, generará 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);
    } 
}

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

Tomemos, por ejemplo, un método que carga los detalles del usuario solicitado desde un archivo de texto.El método supone que existe un archivo de texto con el nombre del ID del usuario y el sufijo ".data".Cuando ese archivo en realidad no existe, 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.Por lo tanto, 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 mejor práctica 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.

Cuando crea una excepción personalizada, aquí tiene una lista de verificación útil:

• Encuentre un buen nombre que transmita por qué se lanzó la excepción y asegúrese de que el nombre termine con la palabra "Excepción".

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

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

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

• Agregue propiedades de excepción personalizadas que puedan 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 poder 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.

Por lo general, se captura y se 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 traducir una excepción en algo más significativo.Por ejemplo, si está escribiendo una capa de acceso a datos y utilizando códigos de error personalizados con SQL Server, puede traducir SqlException en cosas como ObjectNotFoundException.Esto es útil porque (a) facilita que quienes llaman manejen tipos específicos de excepción y (b) porque evita que los detalles de implementación de esa capa, como el hecho de que está usando SQL Server para persistencia, se filtren a otras capas, lo que le 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 sus detalles, lo que ayuda a depurar y diagnosticar problemas activos.Lo ideal sería publicar el error en algún lugar que el equipo de operaciones pueda monitorear fácilmente (p. ej.el registro de eventos), así como en algún lugar que brinde contexto sobre dónde ocurrió la excepción en el flujo de control para desarrolladores (generalmente seguimiento).

Puedo pensar en las siguientes razones:

  • Mantener fijo el conjunto de tipos de excepciones lanzadas, como parte de la API, para que las personas que llaman solo tengan que preocuparse por el conjunto fijo de excepciones.En Java, estás prácticamente obligado a hacer eso debido al mecanismo de excepciones marcadas.

  • Agregar información de contexto a la excepción.Por ejemplo, en lugar de dejar pasar el "registro no encontrado" desde la base de datos, es posible que desee capturarlo y agregar "...mientras procesamos el pedido número XXX, buscamos el producto YYY".

  • Realizar algunas tareas de limpieza: cerrar archivos, revertir transacciones y liberar algunos identificadores.

Generalmente, "Hacer algo" implica explicar mejor la excepción (por ejemplo, envolverla en otra excepción) o rastrear información a través de una determinada fuente.

Otra posibilidad es que el tipo de excepción no proporcione suficiente información para saber si es necesario detectar una excepción, en cuyo caso detectarla y examinarla proporcionará 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 cree que la información de seguimiento puede ser necesaria en algún momento futuro, en cuyo caso obtienes el estilo try {} catch {throw;}, que es No es de ninguna ayuda.

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

Una buena razón sería registrar el error primero en la captura y luego enviarlo 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, esa es la única vez que el error se envía a la pila (esto a veces se hace para el acceso a la base de datos para llamadas a la base de datos que expiran, o en el acceso a servicios web a través de redes lentas).

Sin embargo, habrá muchas otras razones para hacerlo.

Para su información, esta es una pregunta relacionada con cada tipo de relanzamiento:Consideraciones de rendimiento para lanzar excepciones

Mi pregunta se centra en "Por qué" volvemos a generar excepciones y su uso en la estrategia de manejo de excepciones de la aplicación.

Hasta que comencé a usar EntLib ExceptionBlock, los usaba para registrar errores antes de lanzarlos.Es algo desagradable cuando crees que podría haberlos manejado en ese momento, pero en ese momento era mejor que fallaran estrepitosamente en UAT (después de registrarlos) en lugar de cubrir un error de flujo.

Lo más probable es que la aplicación detecte esas excepciones reiniciadas más arriba en la pila de llamadas y, por lo tanto, 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 excepciones de nivel superior que registre o informe las expectativas.

Otra alternativa es que el codificador fue vago y, en lugar de detectar solo el conjunto de excepciones que desea manejar, capturó todo y luego volvió a lanzar solo las que en realidad no pueden manejar.

Como mencionó Rafal, a veces esto se hace para convertir una excepción marcada en una excepción no marcada, o en una excepción marcada que sea más adecuada para una API.Hay un ejemplo aquí:

http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html

Si nos fijamos en las excepciones como en una forma alternativa de obtener el resultado de un método, entonces 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.Normalmente esto sucede en el borde de dos capas de aplicación: cuando una función de la capa B llama a una función desde la capa C, se transforma Cel resultado en BLa forma interna.

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

Si no es así, entonces en la capa A que llama a la capa B Habrá un conjunto completo de excepciones JDK que manejar.:-)

Como también señala la respuesta aceptada, capa A tal vez ni siquiera sea consciente de CLa excepción.

Ejemplo

Capa A, servlet:recupera una imagen y su metainformación
Capa B, biblioteca JPEG:recopila etiquetas DCIM disponibles para analizar un archivo JPEG
Capa C, una base de datos simple:una clase que lee registros de cadena de un archivo de acceso aleatorio.Algunos bytes están rotos, por lo que genera una excepción que dice "no se puede leer la cadena UTF-8 para el registro 'Cita bibliográfica'".

Entonces A No entenderá el significado de "Cita bibliográfica".Entonces B debería traducir esta excepción para A en TagsReadingException que envuelve el original.

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top