¿Por qué la gente de Java consume con frecuencia las excepciones en silencio?

81

Nunca antes hice una codificación seria de Java, pero aprendí la sintaxis, las bibliotecas y los conceptos basados ​​en mis habilidades existentes (Delphi & C #). Una cosa que apenas entiendo es que he visto tanto código que silenciosamente consume excepciones después de printStackTraceesto:

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

Hay un código similar como este en casi todos los artículos y proyectos de Java con los que me encontré. Según mi conocimiento, esto es muy malo. La excepción casi siempre debería reenviarse al contexto externo como este:

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
            throw new AssertionError(e);
        }
    }

La mayoría de las veces, la excepción debería terminar manejándose en el bucle más externo que pertenece al marco subyacente (Java Swing, por ejemplo). ¿Por qué parece la norma codificar así en el mundo Java? Estoy confundido.

Según mis antecedentes, preferiría eliminar printStackTrace por completo . Simplemente lo volvería a lanzar como un aka no controlado RuntimeException(o, mejor aún, AssertionError), luego lo capturaría y lo registraría en el lugar más apropiado: el bucle más externo del marco.

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            throw new AssertionError(e);
        }
    }
Motivo
fuente
56
Yo diría que no es realmente silencioso cuando se imprime el seguimiento de la pila :)
willcodejavaforfood
13
¿Puedo citar a Isaac Waller "Pero su programa no se cierra y continúa, probablemente en un estado indefinido"
Sake
15
@willcodejavaforfood, Tu comentario obtuvo tantos votos y eso me desconcierta aún más sobre la mentalidad típica de Java.
Sake
13
@willcodejavaforfood: es silencioso desde la perspectiva de la persona que llama. La persona que llama no tiene idea de que sucedió algo. Ahora bien, si eso es lo que se pretende, está bien, pero en general, son malas noticias. Además, piense en lo que sucede en un subprograma: el usuario nunca verá la salida (a menos que tenga la consola de Java abierta, que nunca es). Ok, ya nadie usa applets;) Sin embargo, similar para servletm: el usuario final no sabe que sucedió nada, simplemente se guarda en un registro.
Scott Stanchfield
4
El lanzamiento de excepciones en Java es tan frecuente que la mayoría de los codificadores de Java los ignoran porque si realiza la detección de errores correcta, deberá escribir mucho más código ... así que básicamente todos esos programadores de Java hacen esto porque son perezosos.
Trevor Boyd Smith

Respuestas:

203

Siempre he pensado que es similar al siguiente escenario:

"Un hombre recibe un disparo.

Aguanta la respiración y tiene fuerzas suficientes para tomar un autobús.

Diez kilómetros después, el hombre se baja del autobús, camina un par de cuadras y muere ".

Cuando la policía llega al cuerpo, no tienen ni idea de lo que acaba de suceder. Puede que eventualmente lo hayan hecho, pero es mucho más difícil.

Mejor es:

"Un hombre recibe un disparo y muere instantáneamente, y el cuerpo yace exactamente donde ocurrió el asesinato".

Cuando llega la policía, todas las pruebas están en su lugar.

Si un sistema va a fallar, mejor es fallar rápido

Abordar la pregunta:

  1. Ignorancia.
      +
  2. Perezoso

EDITAR:

Por supuesto, la sección de captura es útil.

Si se puede hacer algo con la excepción, ahí es donde debería hacerse.

Probablemente eso NO sea una excepción para el código dado, probablemente sea algo que se espera (y en mi analogía es como una chaqueta antibalas, y el hombre estaba esperando el disparo en primer lugar).

Y sí, la captura podría usarse para lanzar excepciones apropiadas para la abstracción

OscarRyz
fuente
2
Tragar excepciones no está fallando, no importa fallar rápido. Por otro lado, si su contrato de método tiene un parámetro que es una cadena de dígitos y lo está analizando en un entero, puede tragarse la ParseException. Si está escribiendo una funcionalidad específica, defina una excepción personalizada para esa funcionalidad que falla, luego capture las excepciones y lance su excepción personalizada (con la excepción original como argumento). Luego puede fallar rápidamente a algún lugar donde puede ocurrir un comportamiento significativo (mostrar al usuario, enviar correo electrónico, simplemente iniciar sesión, salir de este hilo del servidor, etc.).
JeeBee
21
Espera un minuto ... Primero tengo que dejar de reírme ... Está bien ... Esa fue, con mucho, la respuesta más entretenida a una pregunta que he visto hasta ahora. Transmite mucho el punto. Aunque puede ser muy útil pasar la excepción "hacia arriba en la cadena" para su manejo, es mejor al menos capturar la excepción primero y luego pasarla para que se pueda incluir información útil.
Mr. Will
La excepción no es el error. Lanzar una excepción es el hombre que recibe un disparo, y luego detallar el incidente en una nota y adjuntarla a una paloma mensajera que está entrenada para volar al escuadrón de homicidios más cercano.
Jherico
13
@Oscar, +100 si pudiera. El mal manejo de excepciones es el resultado de la IGNORANCIA y la MALIZ, no de la pereza. Pereza = el menor esfuerzo posible. La estupidez en el manejo de excepciones genera más trabajo, no lo reduce ... por supuesto, generalmente causa más trabajo para alguien más, por eso parece "vago".
James Schek
1
Veo su punto Oscar, pero todo lo que maneja la excepción o el registro que hace es mostrarle que la excepción ocurrió. Si lo lanza completamente hacia arriba en la cadena, le permite saber qué método finalmente invocó la excepción.
Mauro
33

Por lo general, eso se debe a que el IDE ofrece una "solución rápida" útil que envuelve el código ofensivo en un bloque try-catch con ese manejo de excepciones. La idea es que realmente HAGAS algo, pero los desarrolladores perezosos no lo hacen.

Esto es de mala forma, sin duda.

Kris
fuente
2
De acuerdo, el ejemplo dado parece la solución rápida predeterminada de Eclipse, con el comentario // FIXME: eliminado.
JeeBee
2
Bueno, dijiste "Esto es de mala forma, sin duda " y estoy 100% de acuerdo. Sin embargo, algunas otras respuestas y comentarios me hacen sentir mucha curiosidad por la filosofía detrás de esa gran parte (creo) de los desarrolladores de Java.
Sake
4
Realmente desearía que Eclipse hiciera algo drástico allí. Como, e.printStackTrace (); System.exit (1);
Adam Jaskiewicz
4
He cambiado la configuración de mi IDE para generar un cuerpo de captura que lo vuelve a lanzar como RuntimeException. Ese es un valor predeterminado mucho mejor.
Esko Luontola
6
Si estoy seguro de que la excepción nunca debería ocurrir, generalmente lanzo un AssertionError en lugar de RuntimeException como una forma de documentar mi intención.
Esko Luontola
20

Este es un argumento clásico del hombre de paja . printStackTrace()es una ayuda de depuración. Si lo vio en un blog o en una revista fue porque el escritor estaba más interesado en ilustrar un punto que no sea ​​el manejo de excepciones. Si lo vio en el código de producción, el desarrollador de ese código era un ignorante o un vago, nada más. No debe considerarse un ejemplo de práctica común en el "mundo java".

Bill el lagarto
fuente
1
Entonces, ¿está bien que un programador profesional escriba un código incorrecto en un blog o revista y no en producción? prefiero escribir código incorrecto en producción. si un tipo realmente inteligente está usando printStackTrace, convence a la gente para que lo use. Entiendo que el código de excepción es 8 caracteres más largo, pero ...
IAdapter
8
@ABCDE: Estoy totalmente en desacuerdo. ¿Prefieres escribir código incorrecto en producción? ¡Ese es el código que se supone que funciona! Se supone que los artículos de blogs y revistas ilustran un punto. Si el manejo de errores no es el punto, entonces puede ser un desorden. Muchos escritores utilizan un manejo de errores muy simplificado o ninguno en los artículos. Este no es un ejemplo a seguir.
Bill the Lizard
19
  1. Java te obliga a manejar todas las Excepciones explícitamente. Si un método al que llama su código se declara para lanzar FooException y BarException, su código DEBE manejar (o lanzar) esas excepciones. La única excepción a esto es RuntimeException , que es silencioso como un ninja.
  2. Muchos programadores son perezosos (incluido yo mismo), y es muy fácil imprimir el seguimiento de la pila.
AgileJon
fuente
7
Pero su programa no se cierra y continúa, probablemente en un estado indefinido.
Isaac Waller
5
¿Cómo está indefinido el estado si conoce el tipo de excepción? Esa es una pequeña cita linda, pero por lo general el programa PUEDE y TIENE QUE continuar. No desea que toda la aplicación se bloquee por una excepción: dígale al usuario y pídale que vuelva a hacer lo que fuera.
GreenieMeanie
2
La aplicación no se bloqueará si la excepción se maneja correctamente en el nivel más reciente.
Sake
2
Al menos la mitad de las excepciones son "RuntimeExceptions", lo que hace que parezca que solo hay una. Y no es silencioso, y la RutimeException no detectada imprimirá un seguimiento de pila y bloqueará su programa.
Bill K
@greenieMeanie Por lo general, en el desarrollo, quieres que se bloquee con el más mínimo problema; no dejes que los desarrolladores se salgan con la suya y arruinen una llamada; no perdones NADA. Por otro lado, cuando lo envía, desea hacer lo contrario. Registre todas las excepciones de manera invisible y haga todo lo posible para recuperarse y continuar (en lo que Java es realmente bastante bueno).
Bill K
12

Encuentro que a menudo hay 2 razones por las que esto se hace

  1. El programador era vago
  2. El programador quería proteger un punto de entrada en su componente (correcta o incorrectamente)

No creo que este sea un fenómeno limitado a Java. También he visto este tipo de codificación a menudo en C # y VB.Net.

En la superficie es bastante impactante y se ve terrible. Pero realmente no es nada nuevo. Ocurre todo el tiempo en aplicaciones C ++ que utilizan valores de retorno de código de error frente a excepciones. Sin embargo, la diferencia es que ignorar un valor de retorno potencialmente fatal no se ve realmente diferente a llamar a una función que devuelve vacío.

Foo* pFoo = ...;
pFoo->SomeMethod(); // Void or swallowing errors, who knows?

Este código se ve mejor, pero si SomeMethod () dijera que devuelve un HResult, semánticamente no sería diferente a tragarse una excepción.

JaredPar
fuente
3
Creo que la Razón 1 es mucho más común que la Razón 2 para esta pregunta en particular
matt b
2
@matt b, estuvo de acuerdo. La pereza es responsable de una buena parte de los errores que soluciono estos días.
JaredPar
ignorar un código de error es muchísimo más rápido y utiliza mucho menos código repetitivo.
gbjbaanb
11

porque las Excepciones marcadas son un experimento fallido

(¿quizás printStackTrace () es el verdadero problema ? :)

dfa
fuente
17
No son un experimento fallido. De hecho, ¡me gustan! Como lo señalan otras respuestas, los programadores tienden a ser perezosos y simplemente ignoran los casos de error. Dado que las excepciones marcadas le obligan a tratar con ellas, tendrá un mejor código en general. (Si el programador no los ignora en silencio). Además, incluso si no eres perezoso, no puedes olvidar cath una excepción importante porque el compilador te dirá que lo hagas ...
Malax
5
Las excepciones marcadas son un error por varias razones: verifique algunas de ellas mindview.net/Etc/Discussions/CheckedExceptions
dfa
2
+1 no podría estar más de acuerdo. Las excepciones marcadas a menudo hacen que el código sea menos seguro y este es un ejemplo de cómo.
cletus
2
Las excepciones marcadas definitivamente no son perfectas, pero te obligan a enfrentar la realidad de que, a veces, las cosas no salen según lo planeado. Las excepciones no marcadas solo intentan fingir que vivimos en un mundo perfecto donde nada sale mal
mcjabberz
2
@Peter Lawrey: las excepciones marcadas son un fracaso porque personas muy inteligentes como las que vinieron con el increíble marco Swing vomitan y se niegan a usarlas. Y dudo mucho que personas como Joshua Bloch o los que están detrás del marco Spring "no sepan cómo usarlos correctamente". Claro, usted puede tratar correctamente con una excepción comprobada. El verdadero quebrantamiento es que alguien, en algún lugar, pensó que lanzar uno era una práctica aceptable.
Sintaxis T3rr0r
6

Debo decir que me molesta un poco el tono que implica que este tipo de comportamiento laxo en el manejo de errores es algo fundamental para los programadores de Java. Claro, los programadores de Java pueden ser vagos, como cualquier otro programador, y Java es un lenguaje popular, por lo que probablemente verá una gran cantidad de excepciones al tragar código.

Además, como se ha señalado en otro lugar, hay frustraciones comprensibles con la declaración forzada de Java de excepciones comprobadas, aunque personalmente no tengo ningún problema con eso.

Con lo que tengo un problema, supongo, es que estás revisando un montón de artículos y fragmentos de código en la web sin molestarte en considerar el contexto. La verdad es que, cuando está escribiendo un artículo técnico tratando de explicar cómo funciona una API en particular, o cómo comenzar con algo, es muy probable que se salte algunos aspectos del código: el manejo de errores que no es directamente relacionado con lo que está demostrando es un candidato probable para su eliminación, especialmente si es poco probable que ocurra la excepción en el escenario de ejemplo.

Las personas que escriben artículos de esa naturaleza tienen que mantener una relación señal-ruido razonable, y creo que de manera bastante justa eso significa que deben asumir que conoces algunos conceptos básicos sobre el lenguaje en el que te estás desarrollando; cómo tratar correctamente los errores y un montón de otras cosas. Si encuentra un artículo y nota una falta de verificación de errores adecuada, entonces está bien; solo asegúrese de que cuando incorpore esas ideas (pero, por supuesto, nunca el código exacto en sí, ¿verdad?) en su código de producción, se ocupará de todos esos bits y bobs que el autor omitió sensatamente, de una manera que sea más adecuado a lo que está desarrollando.

Tengo un problema con los artículos introductorios de muy alto nivel que tratan estos temas sin volver a ellos, pero tenga en cuenta que no existe una "mentalidad" particular de los programadores de Java con respecto al manejo de errores; Conozco a muchos de sus queridos programadores de C # que tampoco se molestan en lidiar con todos sus problemas.

Robar
fuente
Pero escribir un artículo de alto nivel usando try {...} catch (IOException e) {}es simplemente estúpido (y un TODO NO ayuda). Seguramente engañará a muchos principiantes para que hagan lo mismo. Además, es mucho más escribir que throws IOException, lo cual es correcto la mayor parte del tiempo. Quizás una vez por trabajo, no sea posible y luego escribir throw wrap(e)(sin aburrir a definir wrap) es una buena solución. Una de las primeras cosas que me apoyé en Java es que tragar en silencio es algo terrible y tengo mucho cuidado para no hacerlo ni siquiera temporalmente (incluso fallar es mucho mejor a largo plazo).
maaartinus
5

Una impresión de System.out o e.printStackTrace (), que implica el uso de System.out, suele ser una señal de alerta, lo que significa que alguien no se molestó en hacer un trabajo diligente. A excepción de las aplicaciones Java de escritorio, la mayoría de las aplicaciones Java están mejor utilizando el registro.

Si el modo de falla de un método es una no operación, está perfectamente bien comer una excepción, ya sea que registre el motivo (y la existencia) o no. Sin embargo, lo más común es que la cláusula de captura debería tomar algún tipo de acción excepcional.

Relanzar una excepción es algo que se hace mejor cuando usa la captura para limpiar parte del trabajo en un nivel donde la información necesaria todavía está disponible o cuando necesita transformar la excepción en un tipo de excepción más accesible para la persona que llama.

Tim H
fuente
3

Solo se consume silenciosamente si el bloque de captura está realmente vacío.

En lo que respecta a los artículos, probablemente sean más interesantes para demostrar algún otro punto además de cómo tratar las excepciones. Solo quieren ir directo al grano y tener el código más corto posible.

Sin embargo, obviamente tiene razón, las excepciones deberían al menos registrarse si van a ser 'ignoradas'.

willcodejavaforfood
fuente
3

Como han señalado otros, la razón por la que ve esto es por una de tres razones:

  1. Un IDE generó el bloque try-catch
    • El código fue copiado y pegado.
    • El desarrollador puso el stacktrace para depurar pero nunca regresó para manejar la excepción correctamente

El último punto es el que tiene menos probabilidades de ocurrir. Digo esto porque no creo que nadie realmente depure de esta manera. Pasar por el código con un depurador es una forma mucho más sencilla de depurar.

La mejor descripción de lo que se debe hacer en un bloque de captura se puede encontrar en el Capítulo 9 de Effective Java de Joshua Bloch .

lavar
fuente
2

En C # todas las excepciones son excepciones en tiempo de ejecución, pero en Java tiene excepciones en tiempo de ejecución y excepciones comprobadas, que debe detectar o declarar en sus métodos. Si llama a cualquier método que tenga "throws" al final, debe capturar las excepciones mencionadas allí o su método también debe declarar esas excepciones.

Los artículos de Java generalmente solo imprimen el seguimiento de la pila o tienen un comentario porque el manejo de excepciones es irrelevante para el tema del artículo. Sin embargo, en los proyectos, se debe hacer algo al respecto, según el tipo de excepción.

Chochos
fuente
2

Debería ver esto muy a menudo si el programador hace bien su trabajo. ¡Ignorar la excepción es una mala práctica! Pero hay algunas razones por las que algunos podrían hacer esto y las soluciones más adecuadas:

  • "¡Esto no sucederá!" Seguro, en algún momento "sabes" que esta excepción no sucederá, pero es aún más apropiado volver a generar una excepción en tiempo de ejecución con la excepción que ocurrió como "causa" en lugar de simplemente ignorarla. Apuesto a que ocurrirá en el futuro. ;-)

  • Código de creación de prototipos Si solo está escribiendo sus cosas para ver si funciona, es posible que desee ignorar todas las excepciones que puedan ocurrir. Este es el único caso en el que hago algunas capturas perezosas (arrojables). Pero si el código se convierte en algo útil, incluyo el manejo adecuado de excepciones.

  • "¡No se que hacer!" Vi mucho código, especialmente código de biblioteca, que se traga las excepciones que ocurren porque en esta capa de la aplicación no se puede realizar un manejo adecuado. ¡NO HAGA ESTO! Simplemente vuelva a generar la excepción (ya sea agregando una cláusula throws en la firma del método o envolviendo la excepción en una biblioteca específica).

Malax
fuente
3
Ver atrapar (lanzar) me hizo temblar.
Bill the Lizard
2
Absolutamente. Solo uso catch (Throwable) o throws Throwable en código si estoy jugando. ¡El código "real" no debe incluirlo! período.
Malax
Convenido. Me estremezco porque lo he visto antes. Si otro desarrollador ve que ha escrito catch (Throwable), ¡ha ido demasiado lejos! :)
Bill the Lizard
1
Quiere atrapar (Throwable) en el nivel más alto, incluso si el código cierra el proceso. Intentar cojear junto con un hilo faltante, podría no ser la mejor idea.
Tom Hawtin - tackline
2

Siempre debe reenviarlo o manejarlo adecuadamente en un contexto del mundo real. Sin embargo, muchos artículos y tutoriales simplificarán su código para transmitir los puntos más importantes y una de las cosas más fáciles de simplificar es el manejo de errores (a menos que lo que esté haciendo sea escribir un artículo sobre el manejo de errores, es decir :)). Como el código java verificará el manejo de excepciones, poner un bloque de captura silencioso simple (o declaración de registro) es el método más simple para proporcionar un ejemplo de trabajo.

Si encuentra esto en algo que no sea un código de ejemplo, no dude en reenviar el código a TDWTF, aunque es posible que ya tengan demasiados ejemplos :)

workmad3
fuente
2

Me temo que la mayoría de los programadores de Java no saben qué hacer con las Excepciones, y siempre lo consideran como una molestia que ralentiza la codificación del caso "nominal". Por supuesto que están totalmente equivocados, pero es difícil convencerlos de que ES importante tratar correctamente las excepciones. Cada vez que me encuentro con un programador de este tipo (sucede con frecuencia) le doy dos entradas de lectura:

  • el famoso Thinking In java
  • Un artículo breve e interesante de Barry Ruzek disponible aquí: www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html

Por cierto, estoy totalmente de acuerdo en que es estúpido capturar una excepción escrita para volver a lanzarla incrustada en una RuntimeException:

  • si lo atrapa, MANEJARLO.
  • de lo contrario, cambie la firma de su método para agregar posibles excepciones que usted podría / no podría manejar, para que su interlocutor tenga la oportunidad de hacerlo por su cuenta.
Michael Zilbermann
fuente
No confiaría al 100% en Bruce Eckel en este tema :)
CurtainDog
2

La combinación de excepciones e interfaces comprobadas conduce a la situación de que el código debe manejar ejecuciones que nunca se lanzan. (Lo mismo se aplica a la herencia normal también, pero es más común y más fácil de explicar con interfaces)

Razón: La implementación de una interfaz no puede generar excepciones (marcadas) distintas de las definidas en la especificación de la interfaz. Por esa razón, los creadores de una interfaz, sin saber qué métodos de una clase que implementa la interfaz podrían necesitar lanzar una excepción, podrían especificar que todos los métodos podrían lanzar al menos un tipo de excepción. Ejemplo: JDBC, donde todo y su abuela se declara para lanzar SQLException.

Pero en realidad, muchos métodos de implementaciones reales simplemente no pueden fallar, por lo que bajo ninguna circunstancia lanzan una excepción. El código que llama a estos métodos todavía debe "manejar" la excepción de alguna manera, y la forma más fácil es tragar la excepción. Nadie quiere saturar su código con un manejo de errores aparentemente inútil que nunca se ejecuta.

Erich Kitzmueller
fuente
1
En mi humilde opinión, debería haber una abreviatura de lenguaje para detectar y volver a lanzar excepciones como errores de tiempo de ejecución. Anotar tal taquigrafía dejaría claro tanto en el código como en el comportamiento que tales excepciones deben considerarse como representaciones de condiciones "inesperadas". Tragar es malo, ya que si se lanza una excepción, algo anda muy mal y el código de llamada debería averiguarlo.
supercat
supercat: Me gusta esa idea, pero podría cancelar el beneficio (cuestionable de la OMI) de las excepciones marcadas.
Erich Kitzmueller
Sería mejor si el control fuera una característica de los sitios de captura / lanzamiento y las instancias de excepción en lugar de las clases de excepción, de modo que las excepciones marcadas pudieran propagarse como excepciones no controladas de la misma clase, pero incluso el ajuste y relanzamiento sería una mejora importante en el status quo, y podría agregarse fácilmente como una nueva característica. Sería especialmente útil en los casos en que un método que podría lanzar una excepción marcada por sí mismo llama a otros métodos que se declaran que arrojan la misma excepción pero que no se espera que lo hagan nunca . Si uno de los últimos métodos arroja ...
supercat
... una persona que llama que espera manejar la excepción lanzada desde el método externo no debería capturar una lanzada por los métodos internos, ya que no representaría la condición que la persona que llama estaba esperando. Si estuviera diseñando un marco de tiempo de ejecución desde cero, usaría un mecanismo diferente para las excepciones marcadas y no marcadas, de modo que las excepciones marcadas agregarían una ligera sobrecarga a una llamada de función exitosa, pero tendrían mucha menos sobrecarga cuando se lanza que las excepciones no marcadas (entre otras cosas , una excepción detectada como comprobada no tendría un seguimiento de pila).
supercat
1

Como se señaló, llamar a printStackTrace () no es un manejo realmente silencioso.

La razón de este tipo de "tragar" la excepción es que, si sigue pasando la excepción en la cadena, todavía tiene que manejar la excepción en alguna parte o dejar que la aplicación se bloquee. Entonces, manejarlo en el nivel en que ocurre con un volcado de información no es peor que manejarlo en el nivel superior con un volcado de información.

Sí, ese Jake.
fuente
1

Es una práctica perezosa, nada menos que en realidad.

Por lo general, se hace cuando realmente no le importa la excepción, en lugar de aumentar su trabajo con los dedos.

Mate
fuente
1

No estoy de acuerdo en que volver a lanzar una excepción marcada sea una mejor idea. La captura significa manipulación; si tiene que volver a lanzar, no debe atrapar. En ese caso, agregaría la cláusula throws a la firma del método.

Yo diría que envolver una excepción marcada en una no marcada (por ejemplo, la forma en que Spring envuelve la SQLException marcada en una instancia de su jerarquía sin marcar) es aceptable.

La tala se puede considerar manipulación. Si se cambiara el ejemplo para registrar el seguimiento de la pila usando log4j en lugar de escribir en la consola, ¿eso lo haría aceptable? No hay mucho cambio, en mi opinión.

El problema real es qué se considera un procedimiento de recuperación excepcional y aceptable. Si no puede recuperarse de la excepción, lo mejor que puede hacer es informar el error.

duffymo
fuente
1

Por favor, nunca, nunca, envuelva una excepción marcada en una excepción no marcada.

Si se encuentra lidiando con excepciones que cree que no debería, entonces mi consejo es que probablemente esté trabajando en el nivel de abstracción incorrecto.

Explicaré: las excepciones marcadas y no marcadas son dos bestias muy diferentes. Las excepciones marcadas son similares al antiguo método de devolver códigos de error ... sí, son algo más dolorosos de manejar que los códigos de error, pero también tienen ventajas. Las excepciones no verificadas son errores de programación y fallas críticas del sistema ... en otras palabras, excepciones excepcionales. Al tratar de explicar qué es una excepción, mucha gente se mete en un lío completo porque no reconoce la diferencia en estos dos casos muy diferentes.

CortinaPerro
fuente
Envolver en AssertionError es razonable para mí. AssertionError es la abstracción que se aplica en cualquier lugar, en mi opinión.
Sake
Explicaré: las excepciones marcadas y no marcadas son dos bestias muy diferentes. Las excepciones marcadas son similares al antiguo método de devolver códigos de error ... sí, son algo más dolorosos de manejar que los códigos de error, pero también tienen ventajas. Las excepciones no controladas son errores de programación y fallas críticas del sistema ... en otras palabras, excepciones excepcionales. Al tratar de explicar qué es una excepción, mucha gente se mete en un lío completo porque no reconoce la diferencia en estos dos casos muy diferentes.
CurtainDog
Probablemente estoy entre las personas que se están metiendo en un lío total, como tú lo dices. Sin embargo, mi punto real es por qué permitir que la ejecución continúe mientras tienes la opción de interrumpirla. (con AssertionError o, si lo prefiere, cambie su interfaz para incluir una excepción adicional.
Sake
1
No podría estar más en desacuerdo con la afirmación principal de esta respuesta. La elaboración tiene méritos.
Lawrence Dol
@CurtainDog: las excepciones marcadas son para problemas "esperados". Si el método x tiros FooException (comprobado), en algunos casos, y el método y, que llama X, no espera que se produzca esta situación, entonces, si estos casos no se presentan, representan un inesperado problema; incluso si sucede que hay algo más arriba en la pila de llamadas que espera a FooException, la situación actual no coincidirá con lo que esperaría la persona que llama en sentido ascendente cuando FooExceptionse lanza a.
supercat
1

Porque aún no han aprendido este truco:

class ExceptionUtils {
    public static RuntimeException cloak(Throwable t) {
        return ExceptionUtils.<RuntimeException>castAndRethrow(t);
    }

    @SuppressWarnings("unchecked")
    private static <X extends Throwable> X castAndRethrow(Throwable t) throws X {
        throw (X) t;
    }
}

class Main {
    public static void main(String[] args) { // Note no "throws" declaration
        try {
            // Do stuff that can throw IOException
        } catch (IOException ex) {
            // Pretend to throw RuntimeException, but really rethrowing the IOException
            throw ExceptionUtils.cloak(ex);
        }
    }
}
finnw
fuente
este es un buen truco, pero personalmente preferiría lanzar una excepción más específica con una causa como 'lanzar una nueva ServiceUnavailableException (ex)'
Greg
El método rethrow de ExceptionUtils de Apache hace exactamente esto. Es un buen truco. github.com/apache/commons-lang/blob/master/src/main/java/org/…
Lluis Martinez
1

El verdadero punto de las excepciones es simplificar el manejo de errores y separarlo de la detección de errores. Esto es contrario a la representación de errores mediante códigos de error, donde el código de manejo de errores se encuentra disperso por todas partes y cada llamada que pueda fallar se revisará para el código de retorno.

Si la excepción representa un error (que es la mayoría de los casos), por lo general, la forma más razonable de manejarlo es rescatar y dejar el manejo a una capa superior. Se debe considerar la posibilidad de volver a generar una excepción diferente si se le agrega alguna semántica significativa, es decir, este error es una falla inusual del sistema / problema temporal (red) / este es un error del lado del cliente o del servidor, etc.

De todas las estrategias de manejo de errores, la más ignorante es esconderse o simplemente imprimir un mensaje de error y seguir adelante como si nada.


La gente de Sun quería que el código fuera más explícito y obligó a los programadores a escribir qué excepciones se pueden producir mediante qué método. Parecía ser un movimiento correcto: cualquiera sabrá qué esperar a cambio de cualquier llamada a un método dado su prototipo (puede devolver un valor de este tipo o lanzar una instancia de una de las clases especificadas (o su subclase)).

Pero como resultó con muchos programadores de Java ignorantes, ahora tratan el manejo de excepciones como si fuera un error de lenguaje / "característica" que necesitaba una solución y escriben código de la peor o casi peor manera posible:

  • El error se maneja de inmediato en un contexto no adecuado para decidir qué hacer con él.
  • Se muestra o se ignora en silencio y la computación continúa incluso cuando el código adicional no tiene la posibilidad de ejecutarse correctamente.
  • La persona que llama al método no puede diferenciar si terminó con éxito o no.

¿Cómo escribir de la "manera correcta" que?

  • Indique cada clase base de excepciones que se pueden lanzar en el encabezado del método. AFAICR Eclipse puede hacerlo automáticamente.
  • Haga que la lista de lanzamientos en el prototipo del método sea significativa. Las listas largas no tienen sentido y "lanzar excepción" es flojo (pero útil cuando no te preocupas mucho por las excepciones).
  • Cuando se escribe de la "manera incorrecta", el simple "lanzar Excepción" es mucho mejor y ocupa menos bytes que "intentar {...} atrapar (Excepción e) {e.printStackTrace ();}".
  • Vuelva a lanzar la excepción encadenada si es necesario.
Lispmachine
fuente
0

Si desea que su excepción se maneje fuera del alcance del método actual, no necesita detectarla en realidad, sino que agrega la declaración 'throws' a la firma del método.

Las declaraciones try / catch que ha visto están solo en el código donde el programador decidió explícitamente manejar la excepción en su lugar y, por lo tanto, no lanzarla más.

quosoo
fuente
1
No es cierto: si está implementando un método de interfaz, o anulando un método de superclase, que no tiene una declaración 'throws', entonces no puede simplemente agregar uno. En esos casos, debe envolver la excepción en una RuntimeException o tragarla.
Martin McNulty
0

Creo que los desarrolladores también tratan de considerar la importancia de "hacer lo correcto" en un contexto particular. A menudo, para el código desechable o cuando propagar la excepción hacia arriba no compraría nada porque la excepción es fatal, también podría ahorrar tiempo y esfuerzo "haciendo lo incorrecto".

kmorris511
fuente
0

Por lo general, se tragaría una excepción cuando no puede recuperarse, pero no es crítica. Un buen ejemplo es el IOExcetion que se puede lanzar al cerrar una conexión de base de datos. ¿Realmente quieres colapsar si esto sucede? Es por eso que los DBUtils de Yakarta tienen métodos closeSilently.

Ahora, para la excepción marcada que no puede recuperar pero que son críticas (generalmente debido a errores de programación), no se las trague. Creo que las excepciones deben registrarse lo más cerca posible de la fuente del problema, por lo que no recomendaría eliminar la llamada printStackTrace (). Querrá convertirlos en RuntimeException con el único propósito de no tener que declarar estas excepciones en su método comercial. Realmente no tiene sentido tener métodos comerciales de alto nivel como createClientAccount () arroja ProgrammingErrorException (lea SQLException), no hay nada que pueda hacer si tiene errores tipográficos en su sql o accede a índices incorrectos.

svachon
fuente
0

Por experiencia, tragar una excepción es perjudicial principalmente cuando no está impresa. Ayuda a llamar la atención si falla, y lo haré deliberadamente a veces, pero simplemente imprimir la excepción y continuar le permite encontrar el problema y solucionarlo, y sin embargo, por lo general, no afecta negativamente a otros que trabajan en la misma base de código. .

De hecho, me gusta Fail-Fast / Fail-HARD, pero al menos imprímelo. Si realmente "come" una excepción (que es realmente no hacer nada: {}) le costará DÍAS a alguien encontrarla.

El problema es que Java te obliga a atrapar muchas cosas que el desarrollador sabe que no se lanzarán o que no le importa si lo son. El más común es Thread.sleep (). Me doy cuenta de que hay agujeros que podrían permitir problemas de enhebrado aquí, pero generalmente sabes que no lo estás interrumpiendo. Período.

Bill K
fuente
0

Puede haber muchas razones por las que uno usaría catch Exception. En muchos casos, es una mala idea porque también detecta RuntimeExceptions, y bueno, ¿no sabe en qué estado estarán los objetos subyacentes después de que esto suceda? Eso es siempre lo difícil con condiciones inesperadas: puede confiar en que el resto del código no fallará después.

Su ejemplo imprime el seguimiento de pila para que al menos sepa cuál podría haber sido la causa raíz. En proyectos de software más grandes, es mejor registrar estas cosas. Y esperemos que el componente de registro no arroje excepciones, ya que podría terminar en un bucle infinito (que probablemente matará su JVM).

David Nouls
fuente
0

Si tiene una excepción marcada y no quiere manejarla en un método, debería hacer que el método arroje la excepción. Solo detecta y maneja excepciones si vas a hacer algo útil con él. En mi libro, solo registrarlo no es muy útil, ya que los usuarios rara vez tienen tiempo para leer registros en busca de excepciones o saber qué hacer si se produce una excepción.

Si bien envolver la excepción es una opción, no le sugiero que lo haga a menos que; está lanzando una excepción diferente para que coincida con una interfaz existente o realmente no hay forma de que se lance dicha excepción.

Por cierto: si desea volver a lanzar una excepción marcada, puede hacerlo con

try {
   // do something
} catch (Throwable e) {
   // do something with the exception
   Thread.currentThread().stop(e); // doesn't actually stop the current thread, but throws the exception/error/throwable
}

Nota: si hace esto, debe asegurarse de que la declaración throws para el método sea correcta, ya que el compilador no puede hacerlo por usted en esta situación.

Peter Lawrey
fuente
Solo FTR: Thread#stop()ha sido obsoleto y deshabilitado mientras tanto (arroja UnsupportedOperationException).
maaartinus
-2

porque es una buena práctica. Pensé que todos lo sabían.
pero la fría verdad es que nadie entiende realmente cómo trabajar con excepciones. El estilo de manejo de errores de C tenía mucho más sentido.


fuente
1
El hecho de que un gran número de desarrolladores no asimile las excepciones no significa que el "retorno de error" sea mejor. La forma C de manejar los errores era y sigue siendo un mecanismo terriblemente propenso a errores (juego de palabras). Tragar excepciones (lo que hace este ejemplo, pero no en silencio) es similar a llamar a una función en C sin verificar el valor de retorno. El resultado final es el mismo: el programa "se equivoca". Este ejemplo es solo un caso en el que el manejo de errores de Java es incorrecto C.
Lawrence Dol