Siempre me encuentro luchando con esto ... tratando de encontrar el equilibrio correcto entre intentar / atrapar y que el código no se convierta en este lío obsceno de pestañas, corchetes y excepciones lanzados de nuevo a la pila de llamadas como una papa caliente. Por ejemplo, tengo una aplicación que estoy desarrollando en este momento que usa SQLite. Tengo una interfaz de base de datos que abstrae las llamadas de SQLite, y un modelo que acepta las cosas que entran / salen de la base de datos ... Entonces, si ocurre una excepción de SQLite, debe lanzarse al modelo (que lo llamó ), quién tiene que pasarlo a quien llamó AddRecord / DeleteRecord / lo que sea ...
Soy fanático de las excepciones en lugar de devolver códigos de error porque los códigos de error pueden ignorarse, olvidarse, etc., mientras que una Excepción esencialmente tiene que ser manejada (concedido, podría atrapar y seguir de inmediato ...) Estoy seguro de que tiene que haber una mejor manera de lo que tengo ahora.
Editar: debería haber redactado esto un poco diferente. Entiendo volver a tirar como diferentes tipos y tal, lo redacté mal y es mi culpa. Mi pregunta es ... ¿cómo se mantiene mejor el código limpio al hacerlo? Simplemente comienza a sentirse extremadamente abarrotado para mí después de un tiempo.
fuente
Respuestas:
Piénselo en términos de tipeo fuerte, incluso si no está usando un lenguaje fuertemente tipado; si su método no puede devolver el tipo que esperaba, debería arrojar una excepción.
Además, en lugar de lanzar la excepción SQLException hasta el modelo (o peor, UI), cada capa debe capturar excepciones conocidas y envolver / mutar / reemplazarlas con excepciones adecuadas para esa capa:
Esto debería ayudar a limitar el número de excepciones que está buscando en cada capa y ayudarlo a mantener un sistema de excepciones organizado.
fuente
throws SQLException
un método que no implique que SQL esté involucrado. ¿Y qué sucede si decides que algunas operaciones deberían ir a un almacén de archivos? Ahora tiene que declararthrows SQLException, IOException
, etc. Se saldrá de control.Las excepciones permiten escribir código más limpio porque la mayor parte se ocupa del caso normal, y los casos excepcionales se pueden manejar más adelante, incluso en un contexto diferente.
La regla para manejar (atrapar) excepciones es que debe hacerse por contexto que realmente puede hacer algo al respecto. Pero eso tiene una excepción:
Las excepciones deben detectarse en los límites del módulo (especialmente los límites de la capa) e incluso para encerrarlos y lanzar una excepción de nivel superior que tenga significado para la persona que llama. Cada módulo y capa debe ocultar sus detalles de implementación incluso con respecto a las excepciones (un módulo de montón puede arrojar HeapFull pero nunca ArrayIndexOutOfBounds).
En su ejemplo, es poco probable que las capas superiores puedan hacer algo con respecto a una excepción SQLite (si lo hacen, entonces está todo tan acoplado a SQLite que no podrá cambiar la capa de datos a otra cosa). Hay un puñado de razones previsibles para que cosas como Agregar / Eliminar / Actualizar fallen, y algunas de ellas (cambios incompatibles en transacciones concurrentes) son imposibles de recuperar incluso en la capa de datos / persistencia (violación de las reglas de integridad, fi). La capa de persistencia debe traducir las excepciones a algo significativo en los términos de la capa del modelo para que las capas superiores puedan decidir si volver a intentarlo o fallar con gracia.
fuente
Como regla general, solo debe detectar Excepciones específicas (por ejemplo, IOException), y solo si tiene algo específico que hacer una vez que haya detectado la Excepción.
De lo contrario, a menudo es mejor dejar que las Excepciones salgan a la superficie para que puedan ser expuestas y tratadas. Algunas personas llaman a esto falla rápida.
Debería tener algún tipo de controlador en la raíz de su aplicación para detectar Excepciones no manejadas que han surgido desde abajo. Esto le brinda la oportunidad de presentar, informar o administrar la excepción de manera adecuada.
Ajustar excepciones es útil cuando necesita lanzar una excepción en un sistema distribuido y el cliente no tiene la definición de la falla del lado del servidor.
fuente
Imagina que estás escribiendo una clase de pila. No incluye ningún código de manejo de excepciones en la clase, como resultado, podría producir las siguientes excepciones.
Un enfoque simplista para ajustar las excepciones podría decidir ajustar ambas excepciones en una clase de excepción StackError. Sin embargo, esto realmente pierde el punto de envolver excepciones. Si un objeto arroja una excepción de bajo nivel que debería significar que el objeto está roto. Sin embargo, hay un caso en el que esto es aceptable: cuando el objeto está de hecho roto.
El punto de envolver excepciones es que el objeto debe dar excepciones apropiadas para errores normales. La pila debería elevar StackEmpty, no ArrayIndexError cuando aparece desde una pila vacía. La intención no es evitar lanzar otras excepciones si el objeto o el código están rotos.
Lo que realmente queremos evitar es detectar excepciones de bajo nivel que se hayan pasado a través de objetos de alto nivel. Una clase de pila que arroja un ArrayIndexError cuando emerge de una pila vacía es un problema menor. Si realmente capta ese ArrayIndexError, entonces tenemos un problema grave. La propagación de errores de bajo nivel es un pecado mucho menos grave que atraparlos.
Para traer esto de vuelta a su ejemplo de SQLException: ¿por qué obtiene SQLExceptions? Una razón es porque está pasando consultas no válidas. Sin embargo, si su capa de acceso a datos está generando malas consultas, está rota. No debe intentar volver a envolver su rotura en una excepción DataAccessFailure.
Sin embargo, una excepción SQLException también podría surgir debido a una pérdida de conexión a la base de datos. Mi estrategia en ese punto es detectar la excepción en la última línea de defensa, informar al usuario que se perdió la conectividad de la base de datos y cerrarla. Dado que la aplicación tiene pérdida de acceso a la base de datos, realmente no hay mucho más que se pueda hacer.
No sé cómo se ve tu código. Pero parece que podría estar traduciendo ciegamente todas las excepciones en excepciones de nivel superior. Solo debe hacerlo en un número relativamente pequeño de casos. La mayoría de las excepciones de nivel inferior indican errores en su código. Atraparlos y envolverlos es contraproducente.
fuente