propagacion - throws java
Cuándo atrapar la excepción vs cuándo lanzar las excepciones? (7)
He estado codificando en Java desde hace un tiempo. Pero a veces, no entiendo cuándo debería lanzar la excepción y cuándo debería detectar la excepción. Estoy trabajando en un proyecto en el que hay muchos métodos. La jerarquía es algo como esto-
Method A will call Method B and Method B will call some Method C and Method C will call Method D and Method E.
Entonces, actualmente, lo que estoy haciendo es: estoy lanzando excepciones en todos los métodos y atrapándolo en el Método A y luego registrando como un error.
Pero no estoy seguro de si esta será la manera correcta de hacerlo? ¿O debería comenzar a capturar excepciones en todos los métodos? Entonces, esa es la razón por la cual esta confusión comenzó en mi- ¿Cuándo debería atrapar la Excepción vs Cuándo debería lanzar las excepciones? Sé que es una pregunta tonta, pero de alguna manera estoy luchando por comprender este importante concepto.
¿Puede alguien darme un ejemplo detallado de When to catch the Exception vs When to throw the Exceptions
para que mis conceptos se aclaren en esto? Y en mi caso, ¿debería seguir arrojando la excepción y luego atraparla en el método principal de llamadas A?
Como otros han dicho, como regla general, debes atrapar una excepción cuando realmente puedes manejarla, de lo contrario, simplemente tírala.
Por ejemplo, si está escribiendo un código que lee información sobre un reproductor conectado desde un archivo guardado y uno de sus métodos de E / S arroja una IOException
, entonces desea lanzar esa excepción y el código que invocó el método de load
querría atrapa esa excepción y manejala como corresponde (como desconectar el reproductor o enviar una respuesta al cliente, etc.). La razón por la cual no desea manejar la excepción en el método de load
es porque en el método, no puede manejar la excepción de manera significativa, por lo que delega la excepción a la persona que llama con la esperanza de que pueda manejarla.
Compartiré un patrón que ha salvado mi tocino en uno o dos entornos de producción.
Motivación
Mi objetivo es asegurarme de que el pobre amigo (quizás yo) que está a medianoche tratando de resolver un boleto de soporte sev1, obtenga una buena jerarquía de errores causados por '''', completa con datos tales como ID''s, todo sin sobrecargarse el código.
Método
Para lograr esto, capturo todas las excepciones marcadas y las vuelvo a lanzar como excepciones sin marcar. Luego utilizo una captura global en el límite de cada una de mis capas arquitectónicas (generalmente abstraído o inyectado, por lo que solo se escribe una vez). Es en estos puntos que puedo agregar contexto adicional a la pila de errores, o decidir si registrar e ignorar, o plantear una excepción comprobada personalizada con variables para contener cualquier contexto adicional. En un lado, solo registro errores en la capa superior para detener el ''doble registro'' (por ejemplo, el trabajo cron, el controlador de primavera para ajax)
throw new RuntimeException(checked,"Could not retrieve contact " + id);
Con este enfoque no hay abarrotamiento de las firmas de métodos de su GUI o nivel de negocio al tener que declarar ''throws'' para las excepciones relacionadas con la base de datos.
Un ejemplo de cómo funciona esto en la vida real:
Digamos que el trabajo de mi código es un proceso automatizado para renovar muchas pólizas de seguro. La arquitectura admite una GUI para activar manualmente la renovación de una política. Digamos también que el código postal para el área de calificación está dañado en el DB para una de estas políticas.
Un ejemplo del tipo de registro de error que quisiera lograr sería.
Mensaje de registro: política de marcado 1234 para la intervención manual debido a un error:
Desde Stack Trace: Política de renovación de errores 1234. Retroceso de la transacción ... Esta captura también cubriría errores como guardar errores o la generación de una carta.
De Stack Trace: Causado por: Error Rating Policy 1234 ... Este catch capta errores al recuperar muchos otros objetos, y errores de algoritmo como NPE, etc ...
De Stack Trace: Causado por: Error Recuperando el Área de Calificación 73932 ...
De Stack Trace: Causado por: JPA: inesperado nulo en el campo ''código postal''
Debe manejar la excepción al nivel más bajo posible. Si el método no puede manejar la excepción correctamente, debe lanzarla.
- catch Si tienes un método que se conecta a un recurso (por ejemplo, abre archivo / red)
- lanzar si la clase más alta en la jerarquía necesita información sobre el error
Debería ver la excepción cuando esté en el método que sabe qué hacer.
Por ejemplo, olvídate de cómo funciona realmente por el momento, digamos que estás escribiendo una biblioteca para abrir y leer archivos.
Entonces tienes una clase, por ejemplo:
public class FileInputStream extends InputStream {
public FileInputStream(String filename) { }
}
Ahora, digamos que el archivo no existe. ¿Qué deberías hacer? Si le cuesta pensar en la respuesta, es porque no hay una ... FileInputStream
no sabe qué hacer con ese problema. Entonces lo lanza a la cadena, es decir:
public class FileInputStream extends InputStream {
public FileInputStream(String filename) throws FileNotFoundException { }
}
Ahora, digamos que alguien está usando tu biblioteca. Pueden tener un código que se ve así:
public class Main {
public static void main(String... args) {
String filename = "foo.txt";
try {
FileInputStream fs = new FileInputStream(filename);
// The rest of the code
} catch (FileNotFoundException e) {
System.err.println("Unable to find input file: " + filename);
System.err.println("Terminating...");
System.exit(3);
}
}
}
Aquí, el programador sabe qué hacer, por lo que atrapan la excepción y la manejan.
En general, capture al nivel en el que puede hacer algo útil al respecto. Por ejemplo, el usuario está intentando conectarse a alguna base de datos y falla en el Método D.
¿Cómo quieres manejarlo? Quizás al poner un diálogo diciendo "Lo siento, no puedo conectarme a SERVER / DB" o lo que sea. ¿Es el método A, B o C el que creó esta información de SERVER / DB (por ejemplo, leyendo un archivo de configuración o solicitando la entrada del usuario) e intentó la conexión? Ese es probablemente el método que debería manejar la Excepción. O al menos 1 lejos del método que debería manejarlo.
Realmente varía dependiendo de su aplicación, por lo que este solo puede ser un consejo muy general. La mayor parte de mi experiencia es con Swing / aplicaciones de escritorio, y generalmente puedes familiarizarte con las clases que están haciendo la lógica del programa (por ejemplo, "Controlador") y quién está colocando cuadros de diálogo (por ejemplo, "Ver"). Por lo general, el "controlador" debería detectar la excepción e intentar hacer algo.
En una aplicación web, esto puede ser diferente.
Algún código muy esquelético, la mayoría de las clases no existen, y no estoy seguro si una URL para el DB incluso tiene sentido, pero entiendes la idea. Vagamente Swingish ...
/* gets called by an actionListener when user clicks a menu etc... */
public URL openTheDB() {
URL urlForTheDB = MyCoolDialogUtils.getMeAURL(URL somePreviousOneToFillInTheStart);
try {
verifyDBExists(urlForTheDB);
// this may call a bunch of deep nested calls that all can throw exceptions
// let them trickle up to here
// if it succeeded, return the URL
return urlForTheDB;
}
catch (NoDBExeption ndbe) {
String message = "Sorry, the DB does not exist at " + URL;
boolean tryAgain = MyCoolDialogUtils.error(message);
if (tryAgain)
return openTheDB();
else
return null; // user said cancel...
}
catch (IOException joe) {
// maybe the network is down, aliens have landed
// create a reasonable message and show a dialog
}
}
Por lo general, lanza una excepción cuando desea notificar a la persona que llama sobre el método de algunas fallas.
por ejemplo, entrada de usuario no válida, problemas de la base de datos, interrupciones de la red, archivos ausentes
Se debe lanzar una excepción cuando una función experimenta una falla, es decir, un error.
Una función es una unidad de trabajo, y las fallas deben verse como errores o de otro modo en función de su impacto en las funciones. Dentro de una función f , una falla es un error si, y solo si, impide que f cumpla cualquiera de las condiciones previas de su llamado, logre cualquiera de las propias postcondiciones de f , o restablezca cualquier invariante que comparte la responsabilidad de mantener.
Hay tres tipos diferentes de errores:
- una condición que impide que la función cumpla una condición previa (p. ej., una restricción de parámetro) de otra función que debe invocarse;
- una condición que impide que la función establezca una de sus propias postcondiciones (por ejemplo, producir un valor de retorno válido es una condición posterior); y
- una condición que impide que la función restablezca un invariante que es responsable de mantener. Este es un tipo especial de postcondición que se aplica particularmente a las funciones de miembro. Una condición esencial posterior de cada función de miembro no privado es que debe restablecer las invariantes de su clase.
Cualquier otra condición no es un error y no se debe informar como un error.
Informe un error donde una función detecta un error que no puede manejar él mismo y que impide que continúe en cualquier forma de operación normal o prevista.
Maneje el error en los lugares que tengan el conocimiento suficiente para manejar el error, para traducirlo, o para hacer cumplir los límites definidos en la política de error, como en las líneas principales o en las principales.