java - Excepciones marcadas contra no verificadas en la capa de servicio
jpa service-layer (5)
Aunque estoy de acuerdo con la opinión de que las excepciones no marcadas hacen que la API sea más conveniente, no es para mí el beneficio más importante. En cambio es esto:
Lanzar excepciones sin marcar te ayuda a evitar errores graves.
Este es el por qué. Teniendo en cuenta que diez desarrolladores están obligados a lidiar con excepciones comprobadas, obtendrás veinte estrategias diferentes para lidiar con ellas, muchas de las cuales son totalmente inapropiadas. Aquí están algunos de los malos enfoques más comunes:
- Golondrina. Atrapa la excepción y ignórala por completo. Continúa como si nada hubiera pasado, aunque la aplicación ahora se encuentre en un estado inestable.
- Entrar y tragar. Capture la excepción y regístrela, pensando que ahora somos responsables. Luego sigue como si nada hubiera pasado.
- Misterio por defecto. Capture la excepción y establezca algunos campos en algún valor predeterminado, generalmente sin avisar al usuario sobre ello. Por ejemplo, si no puede cargar los roles de algunos usuarios, simplemente elija un rol de bajo privilegio y asígnele. El usuario se pregunta qué está pasando.
- Misterio tonto / peligroso por defecto. Capture la excepción y establezca algún campo en un valor predeterminado realmente malo . Un ejemplo que vi en la vida real: no puede cargar los roles de un usuario, así que adelante y suponga que es el mejor (es decir, déles un rol de alto privilegio para no molestar a nadie).
- Informe erróneo El desarrollador no sabe lo que significa la excepción y por eso solo se le ocurre su propia idea.
IOException
convierte en "No se puede conectar con el servidor" incluso si establecer una conexión no tiene nada que ver con el problema. - Enmascarar a través de captura amplia, y reportar mal. Intente limpiar el código capturando
Exception
o (ugh)Throwable
lugar de las dos excepciones verificadas que el método realmente lanza. El código de manejo de excepciones no intenta distinguir (por ejemplo) los problemas de disponibilidad de recursos (por ejemplo, algunasIOException
) de los errores de código (por ejemplo,NullPointerException
). De hecho, a menudo elige una de las excepciones de manera arbitraria e informa erróneamente que cada excepción es de ese tipo. - Enmascarar a través de gran intento, y reportar mal. Una variante de la estrategia anterior es poner un montón de llamadas de declaración de excepción en el alcance de un solo bloque grande de prueba, y luego capturar la
Exception
o elThrowable
porque no hay nada más que maneje todas las excepciones que se lanzan. - Abstracción inapropiada de retorno. Reduzca la excepción incluso si la excepción es inadecuada para la abstracción (por ejemplo, volver a enviar una excepción relacionada con los recursos desde una interfaz de servicio que se supone que debe ocultar el recurso).
- Reciclar sin envolver. Vuelva a generar una excepción (ya sea sin marcar o, si no, con la abstracción apropiada), pero simplemente elimine la excepción anidada que le daría a cualquiera la oportunidad de averiguar realmente lo que está sucediendo.
- Respuesta dramática. Responda a una excepción no fatal saliendo de la JVM. (Gracias a esta entrada de blog para este).
En mi experiencia, es bastante más común ver los enfoques anteriores que ver la respuesta correcta. Muchos desarrolladores, incluso los desarrolladores "senior", tienen la idea de que las excepciones deben eliminarse a toda costa, incluso si esto significa ejecutar la aplicación en un estado inestable. Eso está peligrosamente mal.
Las excepciones no marcadas ayudan a evitar este problema. Los desarrolladores que no saben cómo manejar las excepciones tienden a ver las excepciones como inconvenientes que deben superarse, y no se esfuerzan por atraparlas. Por lo tanto, las excepciones simplemente suben hasta la cima, donde ofrecen un seguimiento de la pila y donde pueden manejarse de manera consistente. En el raro caso de que realmente haya algo mejor que hacer que dejar que la excepción crezca, no hay nada que lo detenga.
Trabajo en un proyecto con una capa de servicio heredada que devuelve nulo en muchos lugares si el registro solicitado no existe o no se puede acceder debido a que la persona que llama no está autorizada. Estoy hablando de registros específicos solicitados por ID. Por ejemplo, algo como:
UserService.get(userId);
Recientemente he presionado para que esta API cambie, o se complemente con una nueva API que, en su lugar, genere excepciones. El debate sobre las excepciones verificadas frente a las no verificadas se ha producido.
Tomando una nota de los diseñadores de JPA / Hibernate et al., He sugerido que las excepciones no controladas pueden ser las más apropiadas. Mi argumento es que no se puede esperar razonablemente que los usuarios de la API se recuperen de estas excepciones y en el 99% de los casos podemos, en el mejor de los casos, notificar al usuario de la aplicación que se ha producido algún error.
El hecho de que las excepciones en tiempo de ejecución se propaguen a mecanismos de manejo genéricos obviamente reducirá gran parte de la complejidad y requerirá el manejo de la rama involucrado en el tratamiento de las excepciones de caso límite. Pero, hay una gran preocupación en torno a este enfoque (con razón).
¿Por qué los diseñadores de proyectos como JPA / EJB e Hibernate seleccionaron para ir con un modelo de excepción sin marcar? ¿Hay una muy buena justificación para ello? ¿Cuáles son los pros / contras? ¿Deberían los desarrolladores que usan estos marcos seguir manejando las excepciones de tiempo de ejecución cerca de donde se lanzan con algo así como envoltorios de adaptadores?
Espero que las respuestas a estas preguntas nos ayuden a tomar la decisión "correcta" con respecto a nuestra propia capa de servicio.
En general, es una buena práctica lanzar una excepción RuntimeException cuando su código en el nivel superior no puede manejarlo y no puede hacer nada acerca de la excepción.
En su caso, su API devolverá algún resultado si el resultado es exitoso, y debería devolver un valor nulo si no se encontraron resultados, y luego arrojará una excepción si algo salió mal al realizar la operación.
La excepción puede estar desactivada si solo le muestra el mensaje de error al usuario y no hace nada más sobre el problema.
Por otra parte, si planea tomar algunos pasos alternativos en caso de un problema, entonces debería estar lanzando una excepción marcada.
Por ejemplo, tengo un código que es como -
Deducir el pago y luego enviar los detalles del envío. Si (el envío de los detalles del envío no es exitoso) entonces reembolse el pago, de lo contrario enviará un correo exitoso.
En la lógica anterior, mi lógica de enviar los detalles de envío debe arrojar una excepción comprobada porque, si hay algún problema, debo reembolsar el importe al cliente. Si en este caso lanzo una excepción no verificada, lo único que sucede es que el usuario puede recibir el mensaje de error (a menos que detecte la excepción runtime - Lo que es malo).
Gracias sathwick
Las excepciones sin marcar ayudan a evitar el desorden de códigos. Por ejemplo considera este código
try
{
File file = new File("file");
FileReader fileReader = new FileReader(file);
BufferedReader bufferedReader = new BufferedReader(fileReader);
String temp = "";
StringBuilder result = new StringBuilder("");
while ((temp = bufferedReader.readLine()) != null)
{
result.append(temp);
}
System.out.println(result);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
Manejamos dos tipos de excepciones, pero si no hay un evento accionable que pueda ocurrir al manejar estas excepciones, ¿por qué atraparlas en primer lugar? La respuesta es no lanzar las excepciones verificadas, ya que eventualmente alguna clase de la jerarquía de llamadas tendrá que manejarlo (o se lanzará a la JVM). Si el desarrollador está realmente interesado en manejar esto, atrapa la clase RuntimeException específica que resuelve el problema.
Los bloques de captura que contienen múltiples excepciones ayudan a reducir este desorden
Podría estar equivocado, pero podría estar conectado a la forma en que el contenedor EJB maneja las excepciones. De las mejores prácticas en el manejo de excepciones EJB :
Para usar el servicio de limpieza interno del contenedor EJB, tendrá que hacer que sus excepciones comprobadas se conviertan en excepciones no comprobadas.
Veo la excepción marcada / no marcada en las siguientes perspectivas, (siguiendo la pista del JDK estándar)
Utilice la excepción marcada si su código / biblioteca depende de algún recurso que sea externo a la JVM (por ejemplo, .file / socket / remote api, etc., es decir, JVM no tiene control sobre ella). Su código DEBE manejar todas las posibles condiciones de error que pueda generar la fuente. Esto es para asegurarse de que su programa sea robusto y falle correctamente en caso de que algo esté mal con ese recurso.
Una excepción no comprobada son las condiciones de error grave O los errores reales en su código que generalmente no deben manejarse DESPUÉS de que haya ocurrido. Podría corregir su código para que este error no se muestre en primer lugar. (Ec. NLP, Reparto de clase, Dividir por cero, etc.)