La sentencia try-with-resources de Java

Escrito por picodotdev el .
java planeta-codigo programacion
Comentarios

Java

Una de las novedades que incorporó Java 7 es la sentencia try-with-resources con el objetivo de cerrar los recursos de forma automática en la sentencia try-catch-finally y hacer más simple el código. Aquellas varaibles cuyas clases implementan la interfaz AutoCloseable pueden declararse en el bloque de inicialización de la sentencia try-with-resources y sus métodos close() serán llamados después del bloque finally como si su código estuviese de forma explícita.

Un ejemplo de código que lee una línea de un fichero usando la sentencia try-with-resources es la siguiente de Java 7. Como se observa no es necesario llamar de forma explícita al método close para liberar los recursos de la instancia de la clase BufferedReader.

1
2
3
4
5
public static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

Anteriormente a Java 7 esto se debía hacer de la siguiente manera con unas pocas lineas más de código algo menos legibles.

1
2
3
4
5
6
7
8
public static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();        
    } finally {
        if (br != null) br.close();
    }
}

El código es similar pero no es equivalente. Observesé que require declarar la variable br fuera del ámbito de la sentencia try-catch-finally donde se usa. Además, si se produce una excepción en el bloque try y posteriormente en el bloque finally en Java 6 la excepción del bloque try se enmascara y la que se lanza es la del bloque finally.

La excepción que se lanza en el bloque try y usando el método Throwable.addSuppressed() que se añadió en la API en Java 7 junto con el método Throwable.getSuppressed() se obtienen las excepciones enmascaradas o suprimidas en la sentencia try-with-resources. El orden de ejecución de los bloques de una sentencia try-with-resources es el indicado en los números emitidos con el método println.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import java.io.BufferedReader;
import java.io.FileReader;

public class Main {

    public static void main(String[] args) {
        try {
            readLine();
        } catch (Exception e) {
            e.printStackTrace();
            for (Throwable t : e.getSuppressed()) {
                t.printStackTrace();
            }
        }
    }

    private static String readLine() throws Exception {
        System.out.println("0");
        String line = null;
        Exception exception = null;
        try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
            System.out.println("1");
            throwException(null);
            line = br.readLine();
        } catch (Exception e) {
            System.out.println("2");
            exception = e;
        } finally {
            System.out.println("3");
            throwException(exception);
        }
        System.out.println("4");
        return line;
    }

    private static void throwException(Exception supressed) throws Exception {
        Exception e = new Exception();
        if (supressed != null) {
            e.addSuppressed(supressed);
        }
        throw e;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
0
1
2
3
java.lang.Exception
    at Main.throwException(Main.java:37)
    at Main.readLine(Main.java:30)
    at Main.main(Main.java:8)
    Suppressed: java.lang.Exception
        at Main.throwException(Main.java:37)
        at Main.readLine(Main.java:23)
        ... 1 more
java.lang.Exception
    at Main.throwException(Main.java:37)
    at Main.readLine(Main.java:23)
    at Main.main(Main.java:8)

La mayoría de clases relacionadas con entrada y salida implementan la interfaz AutoCloseable como las relacionadas con el sistema de ficheros y flujos de red como InputStream, también las relacionadas con la conexión de base de datos mediante JDBC con Connection.