2009-10-16 9 views
6

Tengo una reunión de normas de codificación en poco más de una hora y necesito una respuesta rápida a esta.Necesito una fuente autorizada de por qué no debes arrojar o atrapar java.lang.Exception

La sabiduría común entre los programadores con experiencia de Java es que no arrojar o atrapar java.lang.Exception (con raras excepciones, sin juego de palabras). La razón por la que no lo hace es que la declaración

catch (java.lang.Exception ex) {...} 

también capturar las excepciones sin marcar, y en la mayoría de los casos esto no es lo que se pretende.

Ya tenemos una gran cantidad de código heredado escrito por los miembros del equipo existentes donde detectan una subclase de java.lang.Exception, registran un error y vuelven a lanzar la subclase como java.lang.Exception.

tengo que convencerlos de que

  1. que necesitan para dejar de escribir código como este.
  2. código existente que utiliza este anti-patrón tiene que ser fijo

número 2 significa una buena cantidad de refactorización.

Acortará el argumento en la reunión si puedo mostrar un artículo o entrada de blog por uno de los pesos pesados ​​de la comunidad Java que hace este punto (es decir, Joshua Bloch, James Gosling). Mi google-fu no ha encontrado nada hasta ahora.

¿Alguien sabe de un artículo o blog de un respetado gurú de Java que dice que no se debe lanzar o atrapar java.lang.Exception?

Las respuestas rápidas son muy apreciadas.

Dean

+1

sólo quieren mostrar que pregunta: http://stackoverflow.com/questions/237585/java-lang-exception-vs-rolling-your-own-exception Algunas respuestas agradables en ella me – bastianneu

+0

leer eso antes de publicar esto. Un par de respuestas y comentarios dicen lo mismo, pero estoy buscando una autoridad. Esto dará como resultado una buena cantidad de refactorización, por lo que sería útil contar con la opinión de un experto para respaldarme. –

Respuesta

0

supongo que el punto es que si usted no sabe cómo manejar una excepción específica, entonces no debería cogerlo. Debería propagarse a un nivel superior con la esperanza de que pueda saber qué hacer con él. Capturar excepciones demasiado pronto lleva a que se traguen excepciones en silencio y hace que sea imposible hacer algo útil con ellas más allá del registro.

Imagínese lo que sucedería si el constructor de FileInputStream fuera a registrar una excepción internamente si intentó abrir un archivo que no existía, pero no indicó este error en su código. Está bien que el error se registre, pero su código desea detectar esta excepción y hacer algo útil con ella (como solicitar al usuario un nuevo nombre de archivo). Si fueran catch (Exception), no podrías hacer esto.

0

Si tiene a mano una copia de Effective Java de Josh Bloch, sé que cubre el manejo de excepciones con bastante detalle allí. No tengo acceso a él en este momento, así que no puedo resumirlo ni darle referencias de página, pero estoy bastante seguro de que tiene algunos buenos argumentos para no detectar java.lang.Exception.

+1

Ese sería el capítulo 9 (17 páginas). Él no prefiere ninguno de los dos, pero subraya el hecho de que solo debería usar excepciones comprobadas si la persona que llama puede hacer algo sobre el problema. Entonces OOM es un RuntimeExc., Mientras que NoMoreElements es un (excéntrico) excitado comprobado. –

3

No hay puntos en común aquí.Se encuentran dos grupos:

  1. Los que odian excepciones comprobadas se captura y se envuelven en una RuntimeException de algún tipo.

  2. Los que odian RuntimeException

El primer grupo odia al enigma de su código con try...catch, sobre todo porque en la mayoría de los casos, no se puede controlar la excepción cuando se ve por primera vez. Piense en IOException: podría arrojarse por cada byte que leyó. ¿Cuál es el código de bajo nivel que se debe hacer al respecto? Tiene que volver a lanzarlo para que alguien más arriba pueda agregar algún contexto útil al error (como qué archivo estaba leyendo).

El otro grupo quiere ver qué podría salir mal. RuntimeException efectivamente oculta esto.

Hay una solución simple, por cierto: Make Exception extend RuntimException. ¿Insano? Realmente no. Si haces eso con JDK 7, obtienes dos errores de compilación.

El siguiente paso sería hacer que todos los compiladores de Java enumeren todas las excepciones de tiempo de ejecución y enumerarlas en la entrada throws en el archivo de clase. Todavía no tiene que atraparlos, pero ahora, sabrá cuáles podrían suceder.

Por último, extienda los IDEs para mostrar esto. Y listo, ambos grupos podrían ser felices. Lamentablemente, esto no sucederá.

+0

Un poco divagable, ¡pero me gusta! –

+0

Las personas a las que les gustan las excepciones comprobadas no odian las excepciones de tiempo de ejecución, solo limitan su uso a las situaciones en las que son apropiadas. – Brian

+0

@Brian: Mi argumento es que no hay forma de estar de acuerdo cuando son "apropiados". 'SQLException' y' IOException' son claramente excepciones de tiempo de ejecución, desde mi punto de vista, ya que en mi experiencia, se lanzan con más frecuencia debido a un error de programación que a una condición que la persona que llama podría manejar. –

6

Aquí hay algo: Java Tip 134: When catching exceptions, don't cast your net too wide (JavaWorld)

Effective Java (Segunda edición) por Joshua Bloch podría tener algo de esto en el capítulo 9 (Excepciones), aunque no pude encontrar rápidamente cualquier cosa sobre la captura no Exception.

Aquí es a Q&A from JavaWorld sobre la cuestión (también apunta a Java Tip 134) - que también explica por qué a veces hay que romper la regla de no coger Exception o incluso Throwable.

5

Ver this article de Brian Goetz (el asistente de concurrencia) que tiene su propia visión, así como citar Josh Bloch en Java eficaz

2

donde se captura una subclase de java.lang.Exception, registrar un error, y vuelva a lanzar la subclase como java.lang.Exception. Necesito convencerlos de que deben dejar de escribir código como este.

Acepto que deben usar otra táctica, pero por diferentes razones. No tiene mucho sentido capturar una excepción solo para iniciar sesión y volver a lanzarla.

Una alternativa es: no capte la excepción y deje que un código más alto (como un filtro Java EE, o intente/capture su método main) capture y registre todas las excepciones no detectadas. Luego, se asegura de que cada excepción se registre solo una vez y sepa que se registrarán todas las excepciones no detectadas.

Si necesita agregar información adicional a la excepción, recójala, cambie el mensaje y vuelva a lanzarlo.Yo suelo usar una RuntimeException para esto:

} catch (Exception originalException) { 
    throw new RuntimeException("user name was " + userName, originalException); 
} 
+0

Las excepciones se deben registrar lo más cerca posible de donde se lanzaron. Es posible que en algún lugar en sentido ascendente se trague la Excepción, o que ocurra otro Error o RuntimeException (por ejemplo, NullPointerException) que evitará el registro en sentido ascendente. ¿Quisiste decir que tu declaración de catch() arriba también atrapa RuntimeException? –

+0

@Dean Schulze presumiblemente, si se tragó una excepción, eso significa que no fue una excepción inesperada, pero era una esperada y el código sabía cómo manejarla programáticamente. Otra forma de decirlo: quien maneje la excepción debe iniciar sesión. Si no se maneja completamente, debe tener algún mecanismo para manejar y registrar esas excepciones inesperadas. Esto garantiza que el seguimiento de pila solo aparezca una vez en los registros. –

+0

@ Dean Schulze de acuerdo con la declaración catch que captura Exception, sí, estaba intentando mostrar que no es necesario registrar el error y registrar los valores de las variables cuando se detecta la excepción. En cambio, puede capturar la excepción y agregar esos valores al mensaje, luego ajustar la excepción y volver a lanzarla. Sus datos adicionales siguen apareciendo en los registros (y el seguimiento de la pila solo se publica una vez, lo que facilita la búsqueda de errores en los registros). –

1

es un artículo largo, pero this le propone:

  1. uso comprobado excepciones cuando el cliente espera que este error que se produzca con regularidad y debe manejar la situación (por ejemplo: el usuario -entered datos no pasaron la validación)
  2. uso de excepciones sin marcar, para condiciones inesperadas (por ejemplo: servidor de base de datos fue abajo)

En teoría, # 1 (exp Los errores rechazados deberían tener su propio tipo de excepción, y el único lugar que debería capturar un # 2 (una RuntimeException) es algún tipo de controlador de nivel superior que capte la excepción, lo registre y muestre al usuario un mensaje de error, e incluso aquí, probablemente deberías atrapar a Throwable para asegurarte de que se manejan las excepciones no detectadas.

Siguiendo estas pautas, no debe detectar Exception ya que no cumple con ninguno de los criterios anteriores (es decir, no es una RuntimeException y no es una subcasta de excepción especializada para indicar un error esperado).

+1

La URL del artículo al que se hace referencia [ha cambiado] (http://www.oracle.com/technetwork/articles/entarch/effective-exceptions-092345.html). @TerrelShumway publicó el mismo artículo en su respuesta. – hotshot309

+0

@ hotshot309 corregido. ¡Gracias! –

+0

Las personas a las que les gustan las excepciones comprobadas no odian las excepciones de tiempo de ejecución, solo limitan su uso a las situaciones en las que son apropiadas. – Brian

1

Aquí está una muy insightful article

Resumen:

  1. Uso excepciones comprobadas por contingencias raros pero válidos que se relacionan con el propósito de su código. El código del cliente debe saber cómo manejarlos.

  2. Utilice las excepciones no marcadas para las fallas que no deberían suceder pero sí. (Servidor inactivo, classpath mal configurado, error de sintaxis SQL, etc.) El técnico de TI que administra el servidor o el desarrollador que acaba de pasar el SQL incorrecto a prepareStatement() debería saber cómo solucionar estos problemas. Las fallas deberían propagarse hasta la capa de registro para que la información no se pierda.

Cuestiones relacionadas