Excepciones en Java: Lo que (probablemente) estas haciendo mal

Me parece muy interesante el artículo de DZone que habla sobre el uso que tenemos con las excepciones en Java.

Y en esta entrada voy a dejar los puntos que considero más relevantes y la síntesis de lo que he comprendido, pero antes me gustaría comenzar con esta grandiosa frase:

“Utilizar excepciones para controlar el flujo a través de tú programa es una mala prácitca” …

“Las Excepciones deben ser para casos excepcionales”

Y es muy común, cualquiera se deja llevar por la “facilidad” de capturar una excepción y mostrar un mensaje de texto en la consola sobre algún problema o falla,  y después pensar en la forma de evitar que la ejecución se detenga y asegurar  que la aplicación continúe, es decir programamos para evitar errores y no valoramos el manejo de excepciones.

Si tú aplicación tiene una sensible opción de recuperación, no uses una excepción. La mejor forma de manejar una excepción es mostrar una alerta.

Existen dos tipos de excepciones, Marcadas (Checked) y No Marcadas (Unchekecd). Las marcadas te obligan a tratar las excepciones en el código (por ejemplo IOException, FileNotFoundException, etc) y las no marcadas suceden durante el tiempo de ejecución y NO deben ser capturadas (RuntimeException, NullPointerException, AritmethicException, etc).

Ambas tienen un uso particular, pero comunmente muchos desarrolladores tienden a programar para evitar problemas con las excepciones no marcadas y esto es un error, cuando el código genera una excepcion en tiempo de ejecución significa que el desarrollo no tiene un buen diseño o ha ocurrido un caso excepcional (es decir raro o atípico).

Cuando una excepción ocurré podemos tomar dos alternativas para su tratamiento:

  • Mantener la aplicación en ejecución, tener alguna forma manual de inspeccionar el código para asegurar que se encuentra en un estado “correcto” y no dañarlo para garantizar que continua la ejecuciòn. (Esto es lo peor que puedes hacer)
  • Asumir que tú aplicación se ha dañado, detectar una anomalía e informar del caso enviando una alerta y dejar que la ejecuciòn termine sin intentar recuperar su estado (la mejor opción porque puedes identificar áreas de oportunidad para mejorar)

¿Por que es mejor utilizar RuntimeExceptions (no marcadas) vs CheckedExceptinos (marcadas)? Por la propagación, las excepciones marcadas delegan a los métodos que las utilizan la responsabilidad de manejar la excepción y los obliga a generar en la firma del metodo algo cómo “throws SomeException” o llenar el código con bloques try-catch, lo cual genera variantes en el flujo que incrementan la complejidad del desarrollo.

Las viejas ideologías defienden el uso de excepciones marcadas, porque obligan al desarrollador a “manejarlas apropiadamente”, pero esto no sucede así, muchos terminan utilizando la clase Exception para manejar todo.

La sugerencia para mejorar esto es crear tus propias excepciones envueltas en una RuntimeException, esto es muy util a la hora de depurar ya que puedes identificar los errores que tienes y obtener más información especifica del error.

Estas excepciones pueden detener la ejecución de tu aplicación, sin emabrgo causan el efecto deseado, generan un genunio caso  excepcional, el cual se debe identificar para permitir al desarrollador mejorar el código para evitar esta situación excepcional.

Esto se puede realizar mediante la adecuada separación del a funcionalidad y el manejo de excepciones, por ejemplo el uso del patrón decorator.

Veamos un ejemplo, con el patrón composite al invocar el servicio lo envuelves (wrap up) con el  ExceptionHandler:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 InfoPublisher publisher = new InfoPublisher();
        publisher.subscribe(
            new ErrorHandlingSubscriber(
                new CompositeSubscriber(
                    new StoreInfomationSubscriber(),
                    new DoSomethingWithInfoSubscriber(),
                    new AnotherActorSubscriber()
                )
            )
        )

Dentro del composite  se encarga de invocar el evento correspondiente:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 class CompositeSubscriber implements Subscriber{
    private Subscriber[] subscribers;
    public CompositeSubscriber(Subscriber... subscribers) {
        this.subscribers = subscribers;
    }
    @Override
    public void onInfo(String info) {
        for (Subscriber subscriber : subscribers) {
            subscriber.onInfo(info);
        }
    }
}

El handler es el responsable de controlar las excepciones:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class ErrorHandlingSubscriber implements Subscriber{
    private Subscriber subscriber;
    private Logger logger = LoggerFactory.getLogger(ErrorHandlingSubscriber.class);
    public ErrorHandlingSubscriber(Subscriber subscriber) {
        this.subscriber = subscriber;
    }
    @Override
    public void onInfo(String info) {
        try{
            subscriber.onInfo(info);
        }catch (Exception e){
            logger.error("Serious Exception!", e);
            System.exit(1);
        }
    }
}

Considero que es más sencillo realizar este tipo de cosas con técnicas de AOP (utilizar el framework de spring  puede ser una buena alternativa).

En resumen:

  • Nunca utilices Excepciones marcadas ya que incrementan la complejidad en el flujo de control de la aplicación.
  • Envuelve las excepciones marcadas con tus propias excepciones no marcadas, es una mejor alternativa para control y análisis de la aplicación..
  • Genera un mecanismo para manejar las excepciones utilizando un patrón adecuado, separando la funcionalidad para mantener el código mantenible,
  • Permite que la aplicación sea susceptible a lanzar excepciones (y puedas mejorarla cuando en verdad ocurran casos excepcionales).

Referencias

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s