Leí un código de un colega y descubrí que a menudo atrapa varias excepciones y siempre lanza una 'RuntimeException' en su lugar. Siempre pensé que esta es una muy mala práctica. ¿Me equivoco?
java
exceptions
exception-handling
RoflcoptrException
fuente
fuente
Function
,Predicate
, etc.) no han parametrizados lanza cláusulas. Esto significa que necesita atrapar, ajustar y volver a lanzar cualquier excepción marcada en el bucle interno de cualquier método stream (). Eso en sí mismo me ayuda a determinar si las excepciones marcadas son una mala idea.Respuestas:
No conozco suficiente contexto para saber si su colega está haciendo algo incorrectamente o no, así que voy a discutir sobre esto en un sentido general.
No creo que siempre sea una práctica incorrecta convertir las excepciones verificadas en una especie de excepción de tiempo de ejecución . Las excepciones marcadas a menudo son mal utilizadas y abusadas por los desarrolladores.
Es muy fácil usar excepciones comprobadas cuando no están destinadas a ser utilizadas (condiciones irrecuperables, o incluso controlar el flujo). Especialmente si se usa una excepción marcada para condiciones de las cuales la persona que llama no puede recuperarse, creo que está justificado convertir esa excepción en una excepción de tiempo de ejecución con un mensaje / estado útil. Desafortunadamente, en muchos casos, cuando uno se enfrenta a una condición irrecuperable, tiende a tener un bloque de captura vacío, que es una de las peores cosas que puede hacer. La depuración de este problema es uno de los mayores problemas que puede encontrar un desarrollador.
Entonces, si cree que está lidiando con una condición recuperable, debe manejarse en consecuencia y la excepción no debe convertirse en una excepción de tiempo de ejecución. Si se usa una excepción marcada para condiciones irrecuperables, se justifica convertirla en una excepción de tiempo de ejecución .
fuente
Se puede ser bueno . Por favor lee:
http://onjava.com/pub/a/onjava/2003/11/19/exceptions.html
Lanzar excepciones comprobadas y no poder recuperarse de eso no ayuda.
Algunas personas incluso piensan que las excepciones marcadas no deberían usarse en absoluto. Ver http://www.ibm.com/developerworks/java/library/j-jtp05254/index.html
También desde el mismo enlace:
fuente
No, no estas mal. Su práctica es extremadamente equivocada. Debe lanzar una excepción que capture el problema que lo causó. RunTimeException es amplio y exagerado. Debe ser una excepción NullPointerException, ArgumentException, etc. Lo que describa con precisión lo que salió mal. Esto proporciona la capacidad de diferenciar los problemas que debe manejar y dejar que el programa sobreviva frente a los errores que deberían ser un escenario de "No pasar". Lo que está haciendo es solo un poco mejor que "Al reiniciar error después", a menos que falte algo en la información proporcionada en la pregunta.
fuente
Depende.
Esta práctica puede ser incluso sabia . Hay muchas situaciones (por ejemplo, en el desarrollo web), en las que si ocurre alguna excepción, no puede hacer nada (porque no puede, por ejemplo, reparar la DB inconsistente de su código :-), solo el desarrollador puede hacerlo). En estas situaciones, es aconsejable envolver la excepción lanzada en una excepción de tiempo de ejecución y volver a lanzarla. De lo que puede capturar todas estas excepciones en alguna capa de manejo de excepciones, registre el error y muestre al usuario algún buen código de error localizado + mensaje.
Por otro lado , si la excepción no es tiempo de ejecución (está marcada), el desarrollador de la API indica que esta excepción se puede resolver y debe repararse. Si es posible, definitivamente deberías hacerlo.
La otra solución podría ser volver a lanzar esta excepción marcada en la capa de llamada, pero si no pudo resolverla, donde ocurrió la excepción, es probable que tampoco pueda resolverla aquí ...
fuente
exception handling layer
- por ejemplo, en una aplicación web, un filtro.Me gustaría recibir comentarios sobre esto, pero creo que hay momentos en que esto no es necesariamente una mala práctica. (O terriblemente mal). Pero tal vez estoy equivocado.
Muchas veces, una API que está utilizando arrojará una excepción que no puede imaginar que realmente se arroje en su caso de uso específico. En este caso, parece perfectamente correcto lanzar una RuntimeException con la excepción capturada como la causa. Si se lanza esta excepción, es probable que sea la causa del error de programación y no esté dentro de los límites para la especificación correcta.
Suponiendo que RuntimeException no se detecta e ignora más tarde, no está cerca de un OnErrorResumeNext.
OnErrorResumeNext ocurriría cuando alguien detecta una excepción y simplemente la ignora o simplemente la imprime. Esta es una práctica terriblemente mala en casi todos los casos.
fuente
TL; DR
Premisa
Conclusión
Podemos volver a lanzar una excepción marcada como una excepción de tiempo de ejecución si el código de propagación o interfaz supone que la implementación subyacente depende del estado externo, cuando claramente no lo hace.
Esta sección discute el tema de cuándo se debe lanzar cualquiera de las excepciones. Puede pasar a la siguiente barra horizontal si solo desea leer una explicación más detallada de la conclusión.
¿Cuándo es apropiado lanzar una excepción de tiempo de ejecución? Lanza una excepción de tiempo de ejecución cuando está claro que el código es incorrecto y que la recuperación es apropiada modificando el código.
Por ejemplo, es apropiado lanzar una excepción de tiempo de ejecución para lo siguiente:
Esto arrojará una división por cero excepción de tiempo de ejecución. Esto es apropiado porque el código es defectuoso.
O, por ejemplo, aquí hay una parte del
HashMap
constructor de:Para corregir la capacidad inicial o el factor de carga, es apropiado que edite el código para asegurarse de que se pasan los valores correctos. No depende de que algún servidor lejano esté activo, del estado actual del disco, un archivo u otro programa. Ese constructor que se llama con argumentos no válidos depende de la exactitud del código de llamada, ya sea un cálculo incorrecto que condujo a los parámetros no válidos o al flujo inapropiado que omitió un error.
¿Cuándo es apropiado lanzar una excepción marcada? Lanza una excepción marcada cuando el problema es recuperable sin cambiar el código. O para decirlo en términos diferentes, arroja una excepción marcada cuando el error está relacionado con el estado mientras el código es correcto.
Ahora la palabra "recuperar" puede ser difícil aquí. Podría significar que encuentra otra forma de lograr el objetivo: por ejemplo, si el servidor no responde, debe probar el siguiente servidor. Si ese tipo de recuperación es posible para su caso, entonces eso es genial, pero eso no es lo único que significa la recuperación: la recuperación podría simplemente mostrar un diálogo de error al usuario que explica lo que sucedió, o si esa es una aplicación de servidor, entonces podría ser enviando un correo electrónico al administrador, o incluso simplemente registrando el error de manera adecuada y concisa.
Tomemos el ejemplo que se mencionó en la respuesta de mrmuggles:
Esta no es la forma correcta de manejar la excepción marcada. La mera incapacidad para manejar la excepción en el alcance de este método no significa que la aplicación deba bloquearse. En cambio, es apropiado propagarlo a un alcance superior de esta manera:
Lo que permite la posibilidad de recuperación por parte de la persona que llama:
Las excepciones marcadas son una herramienta de análisis estático, dejan en claro para un programador lo que podría salir mal en una determinada llamada sin requerirles que aprendan la implementación o pasen por un proceso de prueba y error. Esto facilita asegurar que no se ignorará ninguna parte del flujo de error. Volver a lanzar una excepción marcada como una excepción de tiempo de ejecución funciona en contra de esta función de análisis estático que ahorra trabajo.
También vale la pena mencionar que la capa de llamada tiene un mejor contexto del esquema más amplio de las cosas como se ha demostrado anteriormente. Podría haber muchas causas para que
dataAccessCode
se llamara, la razón específica de la llamada solo es visible para la persona que llama, por lo que puede tomar una mejor decisión en la recuperación correcta en caso de falla.Ahora que tenemos esta distinción clara, podemos proceder a deducir cuándo está bien volver a lanzar una excepción marcada como una excepción de tiempo de ejecución.
Dado lo anterior, ¿cuándo es apropiado volver a lanzar una excepción marcada como RuntimeException? Cuando el código que está utilizando asume dependencia del estado externo, pero puede afirmar claramente que no depende del estado externo.
Considera lo siguiente:
En este ejemplo, el código se propaga
IOException
porque la API deReader
está diseñada para acceder al estado externo, sin embargo, sabemos que laStringReader
implementación no accede al estado externo. En este ámbito, donde ciertamente podemos afirmar que las partes involucradas en la llamada no acceden a E / S ni a ningún otro estado externo, podemos volver a lanzar la excepción de manera segura como una excepción de tiempo de ejecución sin sorprender a los colegas que desconocen nuestra implementación (y posiblemente asumiendo que el código de acceso IO arrojará unIOException
).La razón para mantener estrictamente marcadas las excepciones dependientes del estado externo es que no son deterministas (a diferencia de las excepciones dependientes de la lógica, que previsiblemente se reproducirán cada vez para una versión del código). Por ejemplo, si intenta dividir por 0, siempre producirá una excepción. Si no divide entre 0, nunca producirá una excepción, y no tiene que manejar ese caso de excepción, porque nunca sucederá. Sin embargo, en el caso de acceder a un archivo, tener éxito una vez no significa que tendrá éxito la próxima vez: el usuario podría haber cambiado los permisos, otro proceso podría haberlo eliminado o modificado. Entonces, siempre tiene que manejar ese caso excepcional, o es probable que tenga un error.
fuente
Para aplicaciones independientes. Cuando sepa que su aplicación no puede manejar la excepción que podría, en lugar de lanzar la RuntimeException marcada, lanzar Error, dejar que la aplicación se bloquee, esperar informes de errores y corregir su aplicación. (Vea la respuesta de mrmuggles para una discusión más profunda de los pros y los contras de verificado versus no verificado).
fuente
Esta es una práctica común en muchos marcos. Por ejemplo,
Hibernate
hace exactamente esto. La idea es que las API no deben ser intrusivas para el lado del cliente yException
son intrusivas ya que debe escribir explícitamente el código para manejarlas en el lugar donde llama a la API. Pero ese lugar podría no ser el lugar correcto para manejar la excepción en primer lugar.En realidad, para ser honesto, este es un tema "candente" y muchas disputas, por lo que no voy a tomar partido, pero diré que lo que hace / propone su amigo no es inusual o poco común.
fuente
Toda la "excepción marcada" es una mala idea.
La programación estructurada solo permite que la información pase entre funciones (o, en lenguaje Java, métodos) cuando están "cerca". Más precisamente, la información solo puede moverse a través de las funciones de dos maneras:
De una persona que llama a una persona que llama, pasando por un argumento de paso
De un llamado a su llamador, como valores de retorno.
Esto es algo fundamentalmente bueno. Esto es lo que le permite razonar sobre su código localmente: si necesita comprender o modificar una parte de su programa, solo necesita mirar esa parte y otras "cercanas".
Sin embargo, en algunas circunstancias, es necesario enviar información a una función "distante", sin que nadie en el medio "sepa". Esto es precisamente cuando hay que usar excepciones. Una excepción es un mensaje secreto enviado desde un generador (cualquier parte de su código puede contener una
throw
declaración) a un controlador (cualquier parte de su código puede contener uncatch
bloque que sea compatible con la excepción que erathrow
n).Las excepciones marcadas destruyen el secreto del mecanismo y, con él, la razón misma de su existencia. Si una función puede permitirse que la persona que llama "conozca" una información, simplemente envíe esa información directamente como parte del valor de retorno.
fuente
Esto podría depender de cada caso. En ciertos escenarios, es aconsejable hacer lo que su amigo está haciendo, por ejemplo, cuando está exponiendo una API para algunos clientes y desea que el cliente sea menos consciente de los detalles de implementación, donde sabe que ciertas excepciones de implementación pueden ser específicas para detalles de implementación y no expuestos al cliente.
Al mantener las excepciones marcadas fuera del camino, puede exponer las API que permitirían al cliente escribir un código más limpio, ya que el propio cliente podría estar validando previamente las condiciones excepcionales.
Por ejemplo, Integer.parseInt (String) toma una cadena y devuelve el número entero equivalente de ella y lanza NumberFormatException en caso de que la cadena no sea numérica. Ahora imagine que un envío de formulario con un campo
age
se convierte a través de este método, pero el cliente ya habría asegurado la validación por su parte, por lo que no tiene sentido forzar la verificación de excepción.fuente
Realmente hay un par de preguntas aquí
La regla general es que se deben verificar las excepciones que se espera que la persona que llama atrape y se recupere. Otras excepciones (aquellas en las que el único resultado razonable es abortar toda la operación o cuando las considere lo suficientemente improbables como para que no valga la pena preocuparse por manejarlas específicamente).
A veces, su juicio sobre si una excepción merece captura y recuperación es diferente de la de la API con la que está trabajando. A veces el contexto importa, una excepción que vale la pena manejar en una situación puede no valer la pena en otra. A veces su mano es forzada por las interfaces existentes. Entonces, sí, hay razones legítimas para convertir una excepción marcada en una excepción no verificada (o en un tipo diferente de excepción marcada)
En primer lugar y lo más importante, asegúrese de utilizar el recurso de encadenamiento de excepciones. De esa forma, la información de la excepción original no se pierde y puede usarse para la depuración.
En segundo lugar, debe decidir qué tipo de excepción utilizar. El uso de una excepción de tiempo de ejecución simple hace que sea más difícil para la persona que llama determinar qué salió mal, pero si la persona que llama está tratando de determinar qué salió mal, eso puede ser una indicación de que no debería haber cambiado la excepción para que no esté marcada.
fuente
En una pregunta booleana, es difícil responder de manera diferente después de dos respuestas controvertidas, pero me gustaría darle una perspectiva que, incluso mencionada en pocos lugares, no estaba lo suficientemente estresada por la importancia que tiene.
Con los años descubrí que siempre alguien está confundido acerca de un problema trivial, carece de la comprensión de algunos de los fundamentos.
Capas. Una aplicación de software (al menos se supone que es) un montón de capas una encima de otra. Una expectativa importante para una buena estratificación es que las capas inferiores brindan funcionalidad para componentes potencialmente múltiples de la capa superior.
Digamos que su aplicación tiene las siguientes capas de abajo hacia arriba NET, TCP, HTTP, REST, DATA MODEL, BUSINESS.
Si su capa de negocios desea ejecutar una llamada de descanso ... espere un segundo. ¿Por qué dije eso? ¿Por qué no dije solicitud HTTP o transacción TCP o envié paquetes de red? Porque esos son irrelevantes para mi capa empresarial. No voy a manejarlos, no voy a mirar los detalles de ellos. Estoy perfectamente bien si están profundamente en las excepciones que obtengo como causa y no quiero saber si existen.
Lo que es más, es malo si conozco los detalles, porque si mañana quisiera cambiar los protocolos de transporte subrayados que tratan los detalles que son específicos del protocolo TCP significa que mi abstracción REST no hizo un buen trabajo para abstraerse de La implementación específica.
Al realizar una transición de una capa a otra, es importante volver a visitar todos los aspectos y el sentido que tendrá para la abstracción que proporciona la capa actual. Puede ser reemplazar la excepción con otra, puede combinar varias excepciones. También podría hacer la transición de marcado a no marcado o viceversa.
Por supuesto, los lugares reales que mencionó tienen sentido es una historia diferente, pero en general, sí, podría ser algo bueno.
fuente
En mi opinión,
En el nivel de marco, deberíamos capturar excepciones de tiempo de ejecución para reducir más bloque de try catch al invocador en el mismo lugar.
En el nivel de aplicación, raramente capturamos excepciones de tiempo de ejecución y creo que esta práctica fue mala.
fuente