usuario tipos propias propagacion por personalizadas nuestras lista jerarquia excepciones ejemplos definidas declaracion crear java exception exception-handling

tipos - Java: ¿dónde y cómo se deben usar las excepciones?



propagacion de excepciones en java (9)

  • ¿Usar try-catch excesivo () tiene un impacto negativo en el rendimiento?

Esto suena como una micro optimización y, si esto realmente tiene un impacto en el rendimiento, tendrás que lidiar con muchos problemas de rendimiento más grandes antes de enfrentarte a este.

  • Usar tipos de excepción específicos es mejor? ¿Qué sucede si me pierdo para detectar uno de los posibles X tipos de excepciones que podrían ocurrir? Francamente, he escuchado y uso un mero 10%, pienso en las excepciones estándar de Java, en 2-3 años. Sí, alguien dijo que si la persona que llama no sabe cómo lidiar con las excepciones trowed, NO DEBERÍA TENER DERECHO a llamar al método de lanzamiento. ¿Está bien?

No estoy seguro de haber entendido la pregunta, pero diría: "Si no sabes qué hacer con una excepción, vuelve a tirarla".

  • He leído este artículo de Anders Hejlsberg, diciendo que las excepciones comprobadas son malas. ¿Debería eso indicar que en algunos casos se aconseja una conveniente excepción a la deglución?

Diablos no. Esto solo significa que la excepción sin marcar debe ser preferida en algunos casos, especialmente cuando el usuario no sabrá qué hacer con una excepción marcada (por ejemplo, una excepción de SQL), o si no hay recuperación posible, ...

  • Una imagen vale 1000 palabras ... supongo que algunos ejemplos ayudarán mucho aquí.

La DataAccessException de Spring es un muy buen ejemplo. Consulte el capítulo 10. Soporte de DAO .

Estaba leyendo algunas cosas sobre el manejo de excepciones en Java, para poder escribir un mejor código. De acuerdo, lo admito, soy culpable; He usado demasiados bloques try-catch {}, he usado ex.printStackTrace() en el catch, ni siquiera usando un logger adecuado (en realidad System.out y System.err fueron redirigidos a un PrintWriter , por lo que log fue generado). Sin embargo, después de algunas horas de lecturas, me encuentro en un lugar extraño: lo desconocido. Si las excepciones están diseñadas para transmitir información sobre estados de flujo anormales, ¿cómo se puede saber DÓNDE está el nivel adecuado para hacer algo con esa información?

Por ejemplo, cuando se produce un error de base de datos, ¿debería uno devolver un valor nulo o un código de error, o lanzar la excepción? Si se lanza, ¿DÓNDE debería manejarse esa excepción? Entiendo que no sirve de nada ni siquiera para registrar una excepción si no puedes hacer nada al respecto. Sin embargo, en aplicaciones GUI, eso podría fácilmente matar tu GUI (estoy usando SWT y lo he visto con demasiada frecuencia), incluso para el caso del método menuShown() (una excepción ArrayIndexOutOfBounds cerrará la aplicación, si no se maneja) . El ejemplo podría continuar para siempre, pero aquí está el resumen de preguntas:

  1. ¿El uso de try-catch () tiene un impacto negativo en el rendimiento?
  2. ¿Es mejor usar tipos de excepciones específicos? ¿Qué sucede si no capté uno de los posibles X tipos de excepciones que podrían ocurrir?
    Francamente, he escuchado y uso un mero 10%. Pienso en las excepciones estándar de Java, en 2-3 años. Sí, alguien dijo que si la persona que llama no sabe cómo lidiar con las excepciones arrojadas, NO DEBERÍA TENER DERECHO de invocar el método de lanzamiento. ¿Está bien?
  3. He leído este artículo de Anders Hejlsberg , diciendo que las excepciones comprobadas son malas. ¿Debería eso indicar que en algunos casos se aconseja una conveniente excepción a la deglución?
  4. Una imagen vale 1000 palabras; Creo que algunos ejemplos ayudarán mucho aquí.

Sé que el tema es eterno, pero en realidad estoy deseoso de revisar un proyecto de tamaño mediano de 150 clases, siguiendo su consejo. Muchas gracias.


  1. Si bien no tengo números, no creo que try-catch tenga un impacto significativo en el rendimiento (no es que lo haya visto). Creo que si no se topan con muchas excepciones, el impacto en el rendimiento será básicamente nada. Pero, en cualquier caso, es mejor preocuparse por la implementación correcta del código primero y lograr un buen rendimiento en segundo lugar; mucho más fácil hacer el segundo una vez que se haya realizado el primero.

  2. Creo que la clase de excepción debe ser específica en cuanto a lo que realmente es la excepción. El problema que tengo con las SQLExceptions de Java es que no te dan información sobre lo que realmente salió mal. Spring utiliza un conjunto de excepciones de bases de datos más descriptivas (excepciones de interbloqueos, excepciones de integridad de datos, etc.). De esta forma, usted puede saber cuál fue realmente el problema.

  3. Las excepciones comprobadas pueden ser molestas, pero no creo que siempre sean malas. Por ejemplo, Spring utiliza excepciones no comprobadas para los errores de la base de datos, pero aún así los compruebo y, o bien 1) los manejo allí mismo, si es posible, o 2) cierro una excepción más general que muestra que el componente falló.

  4. Lamentablemente, no puedo pensar en ninguna buena excepción específica. Sin embargo, como dije, encontré que las reglas de excepción de Spring son útiles y, sin embargo, no molestas, así que tal vez podría consultar algunos documentos de Spring. Las clases de base de datos Spring son un buen ejemplo.


La excepción está allí, por lo que el programador de una Tarea no tiene que lidiar solo con el problema. (1): En caso de que el problema NO sea LÓGICO para que él maneje en la Tarea. Una tarea para leer una Cadena de una secuencia no debería manejar un error de disco, ¿verdad? Pero debería ser muy lógico manejar si los datos no contienen una cadena.

(2): No puede manejarlo solo (no hay suficiente información) Una tarea para leer una Cadena de un archivo y un archivo no encontrado puede solicitar al usuario que seleccione otro archivo, pero ¿cómo puede la tarea ahora qué carpeta puede ser el archivo? extensión del archivo podría ser. Sin saber eso, ¿cómo puede la tarea crear una GUI para volver a preguntar eso?

(3): no existe una forma lógica (o manejable) de distinguir entre diferentes rendimientos. Si una tarea no puede leer el archivo y devolver nulo. ¿Qué pasa si el archivo en el formato incorrecto, también devuelve nulo? ¿Cómo pueden estos dos difieren? Se pueden usar excepciones para diferir eso. Por eso se llama una excepción :-D.

(4): hay muchas tareas similares que requieren un manejo y escritura similar que en todas las tareas es difícil de mantener. Escribir el código de control para todos los accesos puede ser un desastre ya que puede necesitar muchas duplicaciones.

interface DBAccess { public Result accessDB(); } class DBOperation { static public void DoOperation(DBAccess pAccess) { try { return DBAccess.accessDB(); } catch(InvalidDBPasswordException IPE) { // Do anything about invalid password } catch(DBConnectionLostException DBCLE) { // Do anything about database connection lost } // Catch all possible DB problem } } ... private User[] ShowUserList_and_ReturnUsers() { // Find the used. // Show user list if (Users.count() == 0) return null; else return Users; // No need to handle DB connection problem here } private User[] GetUserProfile() { // Find the used and return // No need to handle DB connection problem here } ... /** An onClick event to show user list */ { DBOperation.DoOperation(new DBAccess() { public Result accessDB() { return ShowUserList_and_ReturnUsers(); } }); } /** An onClick event to show a user profile */ { DBOperation.DoOperation(new DBAccess() { public Result accessDB() { return GetUserProfile(); } }); } ... Many more DB access

(5): Escribir todas las comprobaciones de errores complica o ralentiza la tarea. El problema anterior debería mostrar cómo puede ayudar a reducir la complicación. Aquí es cómo ayuda a no desacelerar.

for(int i = 0; i < Users.length; i++) { User aUser = Users[i]; // Do something with user } Replaced with try { for(int i = 0; ; i++) { User aUser = Users[i]; // Do something with user } } catch(ArrayOutOfBoundException AOBE) {}

El código de reemplazo tendrá un mejor rendimiento si la cantidad de usuarios es grande.

Cuando se produce un error de base de datos, ¿debería uno devolver un valor nulo y un código de error o lanzar la excepción? Respuesta: Dependiendo de qué tipo de error. Al igual que si no puede encontrar un usuario, eso no es un error. Pero si la contraseña es incorrecta o la conexión no funciona, estos son errores, ya que tratar de manejarlo de una manera normal complica el programa.

(1) ¿Usar try-catch excesivo () tiene un impacto negativo en el rendimiento? Respuesta: Según "Effective Java", tiene muy poco efecto (solo que no es bueno en loop) por lo que recuerdo (no tengo el libro conmigo aquí ahora).

(2) Usar tipos de excepción específicos es mejor? Resp .: Es mejor evitar el problema específico del usuario.

¿Qué sucede si me pierdo para detectar uno de los posibles X tipos de excepciones que podrían ocurrir? Francamente, he escuchado y uso un mero 10%, pienso en las excepciones estándar de Java, en 2-3 años. Respuesta: Al igual que si manejas el error sin excepción, también puedes perderte. Simplemente agrégalo cuando lo descubras.

Sí, alguien dijo que si la persona que llama no sabe cómo lidiar con las excepciones trowed, NO DEBERÍA TENER DERECHO a llamar al método de lanzamiento. ¿Está bien? Resp .: No, si no sé qué hacer con alguna excepción, vuelva a lanzarla.

(3) He leído este artículo de Anders Hejlsberg, diciendo que las excepciones comprobadas son malas. ¿Debería eso indicar que en algunos casos se aconseja una conveniente excepción a la deglución? Resp: Creo que está hablando de "Verificar excepción" como una característica del compilador para asegurarse de que se debe manejar alguna excepción. La idea de tener una excepción.

(4) Una imagen vale 1000 palabras ... supongo que algunos ejemplos ayudarán mucho aquí. Resp .: el código de arriba.

Tengo la carrera ahora ... Lo siento ... :-p (¡Esté allí en un minuto, cariño!)


La regla general para la excepción es, si puede hacer algo al respecto, atraparlo y manejarlo, si no puede, vuelva a lanzarlo al siguiente método. Para entrar en algunos de sus detalles:

  1. No, usar try / catch excesivo no tendrá un impacto en el rendimiento
  2. Usando el tipo más específico de excepción que puedas. Por ejemplo, generalmente no deberías lanzar Exception si puedes evitarlo. Al arrojar un tipo específico, le está permitiendo al usuario saber qué puede salir mal. Sin embargo, puede volver a plantearlo como algo más genérico, de modo que los llamantes que no estén interesados ​​en la excepción específica no necesiten saberlo (por ejemplo, a una GUI no le importará si se trata de una IOException frente a una ArrayIndexOutOFBoundsException).
  3. Encontrarás personas a las que les gusten más las excepciones comprobadas y encontrarás personas a las que les guste marcar más sin marcar. En general, trato de usar excepciones no verificadas porque generalmente no hay mucho que pueda hacer con la mayoría de las excepciones comprobadas, y aún puede manejar excepciones no verificadas, simplemente no es necesario. Con frecuencia me encuentro replanteando excepciones comprobadas ya que no puedo hacer mucho al respecto (otra estrategia es detectar una excepción marcada y volver a lanzarla como no seleccionada para que las clases más altas de la cadena no tengan que atraparla si no quieren) )

En general, me gusta registrar excepciones en el punto donde se detectan, incluso si no puedo hacer nada al respecto, me ayuda a diagnosticar el problema. Si no está familiarizado con él, también investigue el método Thread.setDefaultUncaughtExceptionHandler. Esto le permite manejar excepciones que no son detectadas por nadie y hacer algo con ellas. Esto es particularmente útil con una aplicación GUI ya que de lo contrario la excepción no se puede ver.

Para entrar en algunos ejemplos:

try { // some database operation } catch (IOException ex) { // retry the database operation. then if an IO exception occurs rethrow it. this shows an example doing something other than just catch, logging and/or rethrowing. }

Estaré encantado de ampliar cualquier parte de esto si lo desea.


Muchas buenas respuestas, permítanme agregar un par de puntos que no se han mencionado.

  1. Sus tipos de excepción deben ser tan específicos como la persona que llama pueda distinguirlos. Con eso quiero decir, si hay dos posibles errores, A y B, y cualquier persona que llama es probable que haga exactamente lo mismo en ambos casos, luego haga una sola clase de excepción. Si es probable que una persona que llama haga dos cosas diferentes, entonces haga dos clases de excepción.

Para muchas, probablemente la mayoría, de las excepciones que creo, lo único que el programa puede hacer de manera realista es mostrar un mensaje de error y darle al usuario la oportunidad de cambiar sus entradas y volver a intentarlo. La mayoría de los errores de validación (formato de fecha no válido, dígitos sin dígitos en un campo numérico, etc.) entran en esta categoría. Para estos, creo un solo tipo de excepción, que generalmente llamo "BadInputException" o "ValidationException", y utilizo esa misma clase de excepción en todo el sistema. Cuando hay un error, lanzo una nueva BadInputException ("La cantidad debe contener solo dígitos") "o algo así, y luego hago que la persona que llama lo muestre y permita que el usuario lo vuelva a intentar.

Por otro lado, si la persona que llama es razonablemente probable que haga cosas diferentes en casos diferentes, haga excepciones diferentes.

Regla práctica sencilla: si tiene dos o más excepciones que SIEMPRE se manejan con un código idéntico y duplicado, combínelas en una única excepción. Si su bloque catch está realizando comprobaciones adicionales para descubrir qué tipo de error es realmente, deberían haber sido dos (o más) clases de excepciones. He visto código que hace exception.getMessage y luego busca palabras clave en el mensaje para descubrir cuál fue el problema. Esto es feo Haga múltiples excepciones y hágalo limpiamente.

  1. Hay tres buenas razones para usar excepciones en lugar de otras formas de manejar errores.

(a) Evita el problema de los valores de retorno "mágicos", como la cadena no nula es una respuesta real pero nula significa que hubo un error. O peor, "NF" significa archivo no encontrado, "NV" significa formato inválido, y cualquier otra cosa es la respuesta real. Con excepciones, una excepción es una excepción y un valor de retorno es un valor de retorno.

(b) Las excepciones omiten claramente la línea principal de código. Por lo general, cuando hay un error, se debe omitir una gran cantidad de procesamiento que no tiene sentido sin datos válidos, y se debe mostrar un mensaje de error y salir, o reintentar la operación, o lo que sea apropiado. En los viejos dados malos, escribiríamos "GOTO panic-abort". Los GOTO son peligrosos por todas las razones que se han discutido mucho. Las excepciones eliminan lo que quizás fue la última buena razón para usar un GOTO.

(c) Tal vez un corrillo de (b), puede manejar el problema en el nivel apropiado. A veces, cuando ocurre un error, desea volver a intentar la misma función, como un error de E / S que podría representar un error de comunicación transitoria. En el otro extremo, puede tener diez niveles de profundidad en las subrutinas cuando se produce un error que no se puede manejar de ninguna manera, sino que se destruye todo el programa y se muestra el mensaje "lo siento, ha habido armageddon, todos están muertos". Con excepciones, no solo es fácil elegir el nivel correcto, sino que puede elegir diferentes opciones en diferentes módulos.


Por favor, no devuelva nulo en caso de errores no fatales. Devuelve un NullObject en su lugar.

De lo contrario, necesitará una verificación nula después de todas y cada una de las llamadas a su código, lo cual es un problema, y ​​si se olvida, el código se bloqueará.


Una cosa que hemos hecho en nuestro equipo es tener excepciones personalizadas para nuestros errores. Estamos utilizando el marco de Hibernate Validator, pero puede hacerlo con cualquier marco o excepciones de stock.

Por ejemplo, tenemos una ValidationException para manejar los errores de validación. Tenemos una ApplicationException para manejar los errores del sistema.

Usted QUIERE minimizar su try-catch-ing. En nuestro caso, el validador recopilará TODAS las validaciones en los objetos "InvalidValue" y arrojará una única ValidationException con la información del valor no válido incluida en ella. Luego puede informar al usuario qué campos estaban equivocados, etc.

En el caso que mencionó de un error de base de datos, es posible que no desee enviar la pila de registro a la UI (iniciar sesión es una buena idea). Este es un caso en el que puede detectar la excepción de la base de datos y luego lanzar su propia ApplicationException a su GUI. Su GUI no tendrá que saber cómo lidiar con una cantidad infinita de errores del servidor, pero puede configurarse para manejar la ApplicationException más generalizada, posiblemente informando que hay un problema con el servidor, e indicando que el usuario debe contactar a su departamento de atención al cliente para reportar el problema.

Por último, a veces no puedes evitar utilizar muchos bloques try / catch debido a las API externas en las que confías. Esto esta bien. Como se mencionó anteriormente, capture la excepción externa y formatéela en una que tenga más sentido para SU aplicación. Luego lanza la excepción personalizada.


Valor de retorno vs. lanzamiento de una excepción

La diferencia fundamental entre una excepción y un valor de retorno es que el valor de retorno se entrega a su llamador inmediato, mientras que una excepción se entrega a una cláusula catch en cualquier parte de la pila de llamadas. Esto permite reutilizar el mismo manejador de excepciones para muchos tipos diferentes de excepciones. Le recomiendo que favorezca las excepciones sobre los códigos de retorno si y solo si necesita esa característica.

Impacto en el rendimiento.

Cada instrucción tiene un efecto negativo en el rendimiento, incluidos aquellos en los bloques de captura. Sin embargo, cualquier CPU moderna puede lanzar y manejar millones de excepciones por segundo, así que a menos que arrojes miles de ellas, no notarás nada.

Excepciones específicas

Para arrojar, sea específico para permitir un manejo específico. Para el manejo, puede ser genérico, pero debe tener en cuenta que se pueden entregar excepciones arbitrarias a su controlador, incluidas las no marcadas que no hayan sido declaradas por sus calles.

comprobado

El debate se debate sobre si los métodos deberían usar excepciones marcadas o no. Nunca tragues una excepción. Manejar o volver a lanzarlo. Simplifica el mantenimiento si no descarta la evidencia de fallas.

Ejemplo

Una aplicación en la que trabajé recientemente recibe comandos sobre la red que luego ejecuta. Esto generalmente implica una mayor interacción con los sistemas remotos, que pueden fallar por una serie de razones. Los métodos para llevar a cabo el comando no captan ninguna excepción, lo que les permite hacer burbujas de la pila de llamadas al manejador central de excepciones en el escucha de comandos, que hace lo siguiente:

for (int retries = 0;; retries++) { try { commandService.execute(command); return; } catch (Exception e} Log.error(e); if (retries < 3) { continue; } else { saveForAnalysis(command, e); alertOperator(); return; } } }

Intencionalmente no captamos y volvemos a lanzar excepciones en la lógica de procesamiento, ya que sentimos que esto no habría agregado ningún valor.


se-radio hizo un episodio de podcast sobre el tema del manejo de errores que explica algunas filosofías sobre cómo usar excepciones, que se pueden replantear como "Dónde absorberlas".

Lo principal que conservé es que la mayoría de las funciones deberían permitirles burbujear, y la mayoría de las excepciones deberían terminar en un archivo de registro. Luego, las funciones solo transmiten mensajes globales que dicen que sucedió algo.

En cierto sentido, esto conduce a una especie de jerarquía de excepciones: una para cada capa de código.

Como creo que dijeron, no tiene sentido explicarle al usuario que ese clúster DB falló porque el DNS no estaba disponible o porque el disco estaba lleno. En ese nivel, sucedió algo que no pudo permitir que se completara la transacción, eso es todo lo que el usuario debe saber.

Por supuesto, los desarrolladores / administradores estarán felices de ver más detalles, es por eso que en la capa de DB, las excepciones específicas deben registrarse.