Excepción: ¿Heredar de Throwable o de Exception?

Ahora que estaba escribiendo una excepcion heredé como de costumbre desde  . Al parecer no tengo broncas con el manejo de escepciones (al implementarlas) pero mi duda es acerca de ¿Cuál es la mejor practica para crear una excepción heredar de   o directamente de  ?.

Tengo por entendido que  tiene definido el comportamiento de un error generado en tiempo de ejecución, osea como el mesero que te trae la comida mientras que   es el Hostess que te recibe en el restaurant y solo te lleva con tu mesero porque   no tiene mas que los constructores definidos por  . Entonces, ¿de cuál es mejor heredar?

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.

Error o Excepcion

Ya veo, la razón por la cuál se hereda desde Exception para indicar una excepción (válgame la redundancia) es porque   tiene como subtipos:   y  .

Complemento con este post para aclarar las diferencias.

Imagen de ezamudio

RuntimeException

Lo mejor sería que heredes de RuntimeException. Así no obligas a nadie a tener que cachar tu excepción o declararla como que se arroja.

Originalmente los tres tipos

- Originalmente

Los tres tipos de excepciones se concibieron para manejarse asi:

Se hereda de Exception cuando no se puede hacer nada (con codigo) para evitar la excepcion.

Por ejemplo revisas que el archivo al que vas a escribir exista, pero cuando empiezas a escribir alguien (otro proceso) lo borra, no puedes hacer nada para evitar que lo borren, pero puedes hacer algo como alternativa y evitar que el programa se muera ( por ejemplo abrir un archivo temporal o regresar un mensaje de error pero seguir funcionando) La excepcion que se lanza en este ejemplo ser'ia IOException ( o alguna subclase ) y la alternativa (el manejo) es lo que se pone en el catch.

Se hereda de RunTimeException cuando se puede hacer algo para evitarlo (con codigo)

Por ejemplo intentas acceder a un indice negativo de un arreglo, se tira ArrayIntexOutOfBounds, o cuando el objeto al que quieres llamar es nulo (NullPointerException). Se podria hacer algo (con codigo) para evitarlo, como revisar los limites o mantener las referencias no nulas dentro de tu programa.

El tercer tipo de exception Error, es cuando hay algo fatal en el entorno del programa y no se puede hacer nada al respecto, ejemplo se acabo la memoria, no tiene caso intentar mandar un mensaje de error (ya no hay memoria para decir que ya no hay memoria )

- En la practica

Con los anios se ha demostrado que no tiene mucho sentido usar el segundo tipo (   ), porque en la mayoria de los casos el codigo que manda la excepcion no puede hacer nada con ella y tiene que dejar que "suba" en la cadena de llamado, con lo cual la firma del metodo va creciendo y creciendo teniendo un monton de excepciones que dejan de tener sentid:

 

Lo mas recomendable es crear una jerarquia de clases que herede de RuntimeException y dejar que la excepcion suba sola hasta el inicio del hilo ( o en alguna clase intermedia que tenga precisamente el manejo de todas las excepciones ) justo como dice Enrique.

Imagen de ezamudio

primero

Entonces quieres decir que el primer tipo (de los que describes) es el que no tiene mucho sentido, es decir, extender Exception.

Imagen de ezamudio

problemas

Y ese problema que describe Oscar con tener que declarar un montón de excepciones en la firma de tu método es lo de menos. Hay dos casos que en lo personal me repatea encontrar:

1. Cuando no quiero manejar una excepción dentro de un método que estoy extendiendo en una interfaz. Por ejemplo si estoy implementando  , mi método   debe cachar cualquier   porque no la puedo declarar en el   del método porque eso altera su firma y el compilador no lo permite. Afortunadamente existe la anotación   en Lombok que permite darle la vuelta a este problema.

2. Cuando extiendo un método que algún genio de Java declaró como  , no me queda de otra más que ponerle lo mismo, aunque no arroje nada realmente. Y cuando lo invoco pues ya me obligaron a aplicar el patrón Pokemon. Sí, commons-pool, estoy hablando de ti....

Diseño de excepciones

Sin dudas diseñar las excepciones es también un tema porque estoy muy de acuerdo con que no todas las excepciones deben ser cachadas pero también no deben de ser todas tratadas hasta que veamos que falló algo en la ejecución. Quizas es que tengo una mala o mas bién incompleta teoria de las excepciones donde típicamente definia DataException, BusinessException y tan tan y una que otra hija de alguna de las anteriores (hacia el front no aplicaba porque tenia reglas de validación). El punto aqui es el diseño de las excepciones, no todas deben ser tratadas hasta que nos haya brincado en la ejecución pero igual es horrible tener que manejar varias excepciones cachadas en las implementaciones.

Ayer modificaba esta clase a la que le incluí   pero ahora la bronca es que no me gustaria que esa excepcion se propague por todo el sistema sino que muera en la siguiente capa de implementación para dar lugar a una excepcion mas ad hoc.Creo que eso seria bronca de quien utilice el método no? pero apoco no seria lindo demarcar el alcance de una excepcion en parte para obligar a que hasta cierto nivel (de capa) se escriba código contingente.

Le eché un lente a Exception Handling Antipattern pero no encontré nada reelevante, en cambio encontré las Effective Java Exceptions para entender un poco mejor.

Imagen de ezamudio

Exception

Que tus excepciones no sean checadas no significa que no las puedas cachar o declarar. Esto es perfectamente válido:

 

La ventaja sobre las excepciones checadas es que no te obligan a hacer el try-catch. En este ejemplo, puedes invocar   sin tener que cachar su excepción pero tampoco tienes que cascadear el   (cosa que no podrías hacer si quisieras, en el  ).

El compilador de Groovy por ejemplo no te obliga a cachar ninguna excepción; ninguna excepción se considera checada en Groovy. Scala y Ceylon tratan de la misma manera las excepciones: no es forzoso cacharlas, ni declarar que se arrojan, pero puedes hacerlo y de hecho es muy recomendable declarar las excepciones que puede arrojar un método, para que alguien las pueda cachar cuando lo invoca, si es que realmente le toca manejarla.

Imagen de Cid

Duda con excepciones

Hola que tal vi este post y pues si intente buscar entre los tantos comentarios que encontre para manejo de excepciones pero todos tienen la mayoria de las preguntas comunes y hasta intente googlear pero nadamas no encontre respuesta espero me puedan ayudar a explicarme esto bueno resulta que hace años tome un curso de cert y ahi ponen un ejemplo de excepciones no checadas (que heredan a RuntimeException), y ya se que esas no estamos obligados a cacharlas pero el ejemplo lo hacia para ver que podiamos manejar las excepciones con el try-catch pero mas alla de eso, me interesa saber porque cuando ejecuto varias veces el codigo con la siguiente linea de comandos

java AddArguments uno 8 tres cuatro
me genera las salidas movidas es decir no coresponden con el orden en que se capturan las excepciones ejemplo:


Cadena sin formato de numero
8
Cadena sin formato de numero
Cadena sin formato de numero
o asi:
8
Cadena sin formato de numero
Cadena sin formato de numero
Cadena sin formato de numero
o asi:
Cadena sin formato de numero
Cadena sin formato de numero
Cadena sin formato de numero
8

aqui dejo el codigo:
 

.println es Synchronized

Es que cuando imprimes con   lo que está pasando es que el hilo que lo ejecuta se queda jetón porque al ser un método   se establece un candado que se liberará cuando termine su ejecución, mientras tanto, en el bucle   estás solicitando la impresión de mas mensajes pero como el   aun está ejecutandose entonces la maquina virtual espera a que termine para ejecutar el siguiente y el siguiente y el siguiente.

Si en vez de imprimirlo directamente pones los mensajes en un array (por ejemplo), notarás que "lo extraño" no sucede al arrojar las excepciones.

Tomando tu código, quedaria así:
 

Imagen de ezamudio

no es synchronized

  no es synchronized, no está pasando nada de lo que dice java.daba.doo (tu aplicación ni siquiera es multi-hilo para empezar). "Lo raro" es porque el mensaje que imprimes cuando cachas la excepción lo estás imprimiendo a STDERR y la suma la estás imprimiendo a STDOUT. Aunque se vean igual en la consola, son dos streams distintos.

Una solución simple es imprimir el mensaje del catch a STDOUT también. Con eso ya todo va a salir en el orden correcto (el 8 al final).

Ah pues si...

Oooops, no habia notado que estaba usando err y out. Efectivamente me fui a un contexto concurrente. Por cierto, segun el código de   (en jdk1.6.0_43) indica que println(...) efectivamente SI es synchronized.

 
(que por cierto, da igual que   por eso mencioné que es sincronizado)

Aunque analizando mejor el asunto, el hecho de que sea   es mas bien para que no se traslape el texto si se llega a invocar al mismo tiempo desde dos o mas hilos.

Una disculpa por el mal diagnostico!

Imagen de ezamudio

doc

En dónde dice que es synchronized? Ah viste fuentes? porque el javadoc no dice nada (yo revisé javadoc 6 y 7 antes de postear)

Imagen de Cid

Gracias

Si bueno pense que como ambos son definidos como PrintStream (err y out) tenian la misma logica, pero desde ahora se que no, ya cambie el err para ver que resultados obtenia al usar ese stream y en algunas consolas cambia hasta de color el texto a rojo (reportando error), otras como el ms-dos no hacen nada las huevonas jajaja.


Cadena sin formato de numero
Cadena sin formato de numero
Cadena sin formato de numero
8

Entonces el println es thread-safe (no se si aplique el termino para lo de syncronized) pero el problema era por la diferencia entre streams out y err, puesto que no genero ningun otro hilo mas que el de main gracias de todas formas a java.dava.doo y por supuesto a ezamudio.

Imagen de beto.bateria

Y el usuario apa?

Existe una parte importante en el manejo del error y es ¿que se le va a mostrar al usuario?, ¿Se le va indicar que se comunico la app con el servidor, pero el servidor no hizo nada?, ¿Se le va a decir al usuario que tiene poco cerebro por no saber que algunos elementos de la division no pueden contener ceros?, ¿O simplemente se cerrara la aplicacion sin decir adios?, o peor aun, ¿se mostrara la pantalla sin informacion? o mas peor :P ¿no se le dira al usuario que se "medio hizo" la transaccion?

Eh?

Si te refieres a los   como subclase de   no hay mucho que hacer, de hecho ese tipo es Fatal. Si quisiste referirte a error como una subclase de   (como el caso en el que indicas  ) mas bien debe ser una regla de negocio ¿Qué hacer en caso de error?

Si estas persistiendo varios numeros y en uno de ellos el cociente no pudo definirse porque el denominador es 0, pos para empezar eso se tiene que validar. No esperes a que truene para saber que hacer. Si el usuario te dice que dividas A/B y de repente te sale un error de la VM indicando que el codigo no puede ejecutarse porque los datos no son aptos para tal operacion... ¿Quien es mas bobo?.

Cuando estas en etapas de pruebas muchos testers ponen datos estupidos pero no significa que ellos lo sean (en la mayria de los casos), simplemente quieren asegurarse que el código que escribiste es lo menos defectuoso posible. Si hay errores y si eres bueno programando seguro serán huecos en las reglas de negocio, de otra forma es señal de que hay que mejorar tu código.

En conclusión, creo que esos ejemplos que mencionas son mas bien cuestiones de negocio, no tanto broncas de mecanismo de las Excepciones en el lenguaje. Son pocas las excepciones que creo que si es necesario esperar a que ocurran para aceptarlas como validación, por ejemplo, si intentas convertir de un string a número, solamente hasta que salió el   nos damos cuenta que no es un string que representa a un numero. Pero por ejemplo divisiones entre 0, seguro se puede validar sin necesitad de una excepcion.

Imagen de echan

un clasico mas de checked vs unchecked exceptions

Regla simple, citando a Bloch en Effective Java

Usa checked exceptions para una condición recuperable y runtime exceptions para errores de programación

A)Checked. Si en mi código se que puede haber bronca y quiero que el que lo vaya usar lo sepa pongo algo que sea Throwable.

B) Unchecked. Realmente me vale un cacahuate si lo quiere cachar o validar. Si detecto algun mal uso de mi código (por ejemplo valor de un parametro inadecuado) aviento un RuntimeException.

Todo esto sigue siendo debatible incluso hay lenguajes que quitaron los checked exception de su especificacion por ser demasiado ruidosos(C#, Scala, ¿algun otro?).

Link interesate

Imagen de ezamudio

no

A) checked - usas una subclase de Exception (no uses directamente Exception).

B) unchecked - ahí sí, usas una subclase de RuntimeException (o directamente RuntimeException).

Groovy convierte todas las excepciones a RuntimeException. Nunca es necesario que caches nada si no quieres.

Ceylon igual, todas las excepciones son de tiempo de ejecución, nunca te obliga a cachar algo.

Imagen de Cid

Era una cuestion pedagogica

Pues si era un ejemplo pedagogico y como mencionan tanto NumberFormatException como ArithmeticException heredan de RuntimeException (no checadas o no marcadas) y segun entiendo este tipo de excepciones no es necesario capturarlas o no deberiamos siguiendo buenas practicas (no se si sea o no tan buena practica) ya que este tipo de excepciones son porque hay errores en la lógica de nuestros programas provocados por uno mismo.

Aunque bueno en mi código original que repito era pedagogico no dividian nada o si ? podria sugerir colocar un if y la comprobacion de la division entre 0 (solo cuando sean enteros) o algo mas adecuado un assert que compruebe que el divisor es diferente de 0 y ya si me da el AssertionError pues ya me chingue y a corregir el bug del programa.

Imagen de bferro

El caso 2 que escribes no es necesario enrique

Cuando anulas (override) un método que heredas de una clase y ese método dispara una excepción, NO estás obligado a que el nuevo método dispare excepción alguna. No violas el contrato que establece la clase base. Lo contrario, anular un método que no dispara excepciones con una nuevo método que sí las dispara se prohíbe pues en ese caso estás violando el contrato que establece la clase base.
Si un objeto de la nueva clase es visto por una referencia a la clase base, tendrás que try/catch, aunque el nuevo método no dispare la excepción.

Imagen de ezamudio

cierto

Lo acabo de probar, es correcto; nunca me había fijado que se puede ocultar la excepción en las subclases, obvio siempre y cuando no se invoque al método de la clase padre porque entonces se debe declarar la excepción, pero ya es por el método invocado y no por el que se extiende.

Esto es útil al momento de implementar la subclase, pero no tan útil al momento de utilizarla ya que si se codifica contra la clase padre (o interfaz por lo general), pues hay que cachar la excepción, aunque nunca se arroja en la subclase utilizada al momento de la ejecución...

Imagen de bferro

Es LSP

En general, si deseas que la jerarquía de clases cumpla con LSP, entonces una subclase NO debe imponer ninguna restricción sobre las condiciones que establece la clase base, pero si puede relajar esas condiciones.