Mejora en el manejo de recursos con Java 7 – ARM

Java 7 añade nuevas características bastante interesantes como son mejoras en la JVM, posibilidad del uso de String en los switch, formatos binarios de números… Entre estas nuevas características se encuentra la sentencia try-with-resources o ARM (Automatic Resource Management). Hasta ahora el manejo de los recursos, como ficheros, sockets, streams o conexiones a base de datos, debía ser realizado por el los programador, con los posibles errores que ésto puede originar. Con esta nueva sentencia, la JVM es la encargada de manejar todos los recursos que sean declarados dentro de la sentencia try-with-resources.

Antes de Java 7

Antes de Java 7 los recursos se solían manejar dentro de un bloque try-catch-finally, de forma que dentro del bloque try se utilizaban los recursos y en el bloque finally se cerraban todos los recursos abiertos. Ésto podía causar problemas de memoria y de rendimiento cuando se olvidaba cerrar estos recursos. Un ejemplo de esta forma de manejar los recursos sería:

Uso del ARM

Ahora si se utiliza la sentencia try-with-resources nos quedaría el siguiente método:

Como se puede observar el código es más sencillo y más fácil de leer, reduciendo bastante el número de líneas y también se elimina el bloque finally para el cierre de recursos.

En este ejemplo, el recurso declarado en la sentencia try-with-resources es un BufferedReader. La declaración aparece entre paréntesis a continuación del try, de esta manera la instancia declarada en la sentencia try-with-resource será cerrada automáticamente cuando el bloque de sentencias del try sean ejecutadas completamente o cuando se produzca una excepción.

de la sentencia se pueden declarar tantos recursos como sea necesario, cerrándose de manera inversa a como han sido declarados:

En este caso, primero se cerraría el ResultSet y a continuación el Statement.

¿Qué hay nuevo en el API?

Para permitir el uso del ARM se ha añadido el interfaz java.lang.AutoCloseable en el API, este interfaz contiene únicamente la definición del método close().

Este interfaz es padre del interfaz java.io.Closeable del que heredan todos los recursos de entrada y salida. El método close() es que se invoca para el cierra todos los recursos incluidos en la cabecera de la sentencia try, llamándose automáticamente una vez finalizado el bloque try o después de producirse una excepción. De manera que todos los recursos declarados en la cabecera del bloque try deberán implementar AutoClosable o Closable. Si se declara algún recurso que no herede de AutoClosable se producirá un error de compilación.

Aunque como se indica en el API, la implementación de este método no es obligatoria, aunque si es aconsejable para un mejor manejo de los recursos. De esta manera, cada una de las clases que hereden de Closeable se encargara de implementar específicamente el método close(). Por ejemplo, la implementación de este método en la clase BufferReader sería:

Uso con JDBC

Otro posible uso es en el manejo de base de datos con JDBC. Antes de java 7, todos los recursos debían ser cerrados manualmente una vez finalizado su uso, dando la posibilidad de olvidar cerrar alguno y producir graves errores en la base de datos.

Ahora con la nueva sintaxis, el mismo código quedaría de la siguiente manera:

Las variables connection, prepared statement y result set son creadas en la sentencia try y después de que se iteren sobre todos los resultados, cuando el bloque termina, la JVM automáticamente cierra todos los recursos.

Manejo de excepciones

El manejo de excepciones es un poco diferente entre try-catch-finally y try-with-resources. Si las excepciones son lanzadas en el bloque try y en el finally, en un try-catch-finally se devuelve la excepción lanzada en el bloque finally mientras que si en una sentencia try-with-resources el metodo devuelve la excepción lanzada por el bloque try. Unos ejemplos podrian ser:

La salida del programa será:

Esto se debe a que la excepción producida en el método close() es ocultada en la primera excepción. A este tipo de excepciones se le llama “suppressed exceptions”. Se pueden recuperar con el método getSuppressed() de la clase Throwable.

Creación de un recuros AutoClosable

Para crear un recurso que pueda ser utilizado en una sentencia try-with-resources, necesitamos implementar el interfaz AutoCloseable. Como se ha dicho anteriormente el interfaz AutoClosable únicamente tiene un método close(). Una simple implementación podría ser:

La salida del ejemplo será:

Java Language Specification

Como se dice en Java Language Specification, la estructura:

Es convertido a la siguiente estructura:

Como se puede ver al final tenemos la misma estructura que se ha utilizado siempre en un bloque try-catch-finally, pero con una sintaxis más sencilla y menos propensa a cometer errores en el uso de recursos.

Enlace | The try-with-resources Statement