21 marzo 2011

Checked vs. unchecked exceptions

Después de desarrollar durante una semana una librería de clases en java me he vuelto a plantear una pregunta que ya tenía algo olvidada en el fondo del subconsciente: ¿excepciones checked o unchecked? Ya sé que es una pregunta muy sobada y seguro que todos tenéis vuestra propia opinión al respecto pero vamos a recordar un poco el debate.

Java soporta los dos tipos de excepciones: checked y unchecked. Java obliga a declarar en la signatura de los métodos todas las excepciones checked que pueda lanzar ese método y todos los métodos que llamen al método deben o capturarlas y tratarlas en un bloque try-catch o declararlas en la firma del método. Por el contrario, las excepciones unchecked que no deben declararse.

La cuestión que se nos plantea al diseñar una librería de clases en java es: ¿Hacemos que nuestras excepciones sean checked o, por el contrario, las hacemos unchecked? Parece evidente que java se diseño para que usáramos checked exceptions en nuestros desarrollos y la posición “oficial” de Oracle al respecto así lo indica (podéis ver la postura oficial de Oracle en este enlace): las excepciones que creamos en nuestras librerías de clases deben ser checked por norma, solo la máquina virtual debería lanzar unchecked exceptions ya que estas solo deben usarse para indicar problemas de programación que el cliente no puede tratar:

“Here's the bottom line guideline: If a client can reasonably be expected to recover from an exception, make it a checked exception. If a client cannot do anything to recover from the exception, make it an unchecked exception.”

Esta postura “oficial” tiene sus defensores y sus detractores, veamos por encima algunos de estos argumentos:

  • El hecho de que el compilador te fuerce a tratar o a propagar explícitamente una excepción asegura que no nos olvidemos de tratarlas. ¿Cuántas veces habéis visto algo del estilo try… catch(Exception e) {e.printStackTrace()}, o, todavía peor try… catch(Exception e) { }?
  • Con el uso de excepciones unchecked es más fácil olvidar el tratamiento de errores por qué el compilador no te fuerza a tratarlas. Si usas unchecked exceptions cualquier parte de tu librería puede lanzar excepciones y como eres consciente de ello, eres más cuidadoso al tratar los casos de error. Tened en cuenta que aunque uses checked exceptions se pueden producir unchecked exceptions en cualquier llamada (NullPointerException, etc…)
  • Las excepciones unchecked se deben documentar incluso mejor que las checked: la documentación en este caso es el único mecanismo que tiene el usuario de la librería de conocer las excepciones que lanza un método, no tendrá ninguna ayuda del compilador.
  • Las excepciones checked exponen los detalles de la implementación en niveles de abstracción muy diferentes. Cuantas veces habéis visto métodos de negocio que tratan o propagan SQLException sin que el método tenga (en este nivel de abstracción) nada que ver con SQL.
  • Las excepciones checked provocan inestabilidad en las firmas de los métodos. Si cambia la implementación de un método que lance excepciones checked se deben cambiar las firmas de todos los métodos que propaguen esas excepciones para adecuarlas a la nueva implementación. El hecho de que las excepciones formen parte de la interface hace que sea difícil añadir o quitar excepciones en posteriores versiones.
  • El uso de checked exceptions puede provocar código poco claro y muy enrevesado. Los bloques try…catch en el código mezclan la lógica de negoció con el tratamiento de las excepciones y hacen que el código resultante sea liado y poco claro.
  • El uso de checked exceptions puede provocar Shallowing (no hacer nada en el catch o hacer catch muy generales de Exception son muestras claras de shallowing).

Creo que nadie discute que la introducción de las excepciones en los lenguajes de programación es una excelente decisión que nos proporciona una forma unificada de tratar las condiciones de error que se producen durante la ejecución de nuestros programas, el tema es si se debe obligar a declarar y verificar las excepciones que lance un método, o, por el contrario, se puede dejar al programador la decisión de que excepciones quiere tratar.

Como todo el mundo, inicialmente construía mis librerías de clases usando excepciones checked. Después de leer a varios “gurus” debatir sobre este tema y reflexionar sobre los “pros” i los “contras” de cada una de las posturas, decidí usar unchecked exceptions en mis desarrollos y me ha proporcionado más beneficios que problemas. I vosotros, ¿qué opináis? ¿usáis unchecked exceptions en vuestros desarrollos?

Fuentes:

No hay comentarios: