La declaraci贸n try-with-resources en Java

    Introducci贸n

    try-with-resources es uno de los varios try declaraciones en Java, destinadas a liberar a los desarrolladores de la obligaci贸n de liberar los recursos utilizados en un try bloquear.

    Inicialmente se introdujo en Java 7 y la idea subyacente era que el desarrollador no necesita preocuparse por la administraci贸n de recursos para los recursos que usan solo en un bloque try-catch-finalmente. Esto se logra eliminando la necesidad de finally blocks, que los desarrolladores solo usaron para cerrar recursos en la pr谩ctica.

    Adem谩s, el c贸digo que usa try-with-resources suele ser m谩s limpio y legible, por lo tanto, hace que el c贸digo sea m谩s f谩cil de administrar, especialmente cuando se trata de muchos try bloques.

    Sintaxis

    La sintaxis de try-with-resources es casi id茅ntica a la sintaxis habitual de try-catch-finalmente. La 煤nica diferencia son los par茅ntesis despu茅s de try en el que declaramos qu茅 recursos usaremos:

    BufferedWriter writer = null;
    try {
        writer = new BufferedWriter(new FileWriter(fileName));
        writer.write(str);  // do something with the file we've opened
    } catch (IOException e) {
       // handle the exception
    } finally {
        try {
            if (writer != null)
                writer.close();
        } catch (IOException e) {
           // handle the exception
        }
    }
    

    El mismo c贸digo escrito usando try-with-resources se ver铆a as铆:

    try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){
        writer.write(str); // do something with the file we've opened
    }
    catch(IOException e){
        // handle the exception
    }
    

    La forma en que Java entiende este c贸digo:

    Los recursos abiertos entre par茅ntesis despu茅s de la instrucci贸n try solo ser谩n necesarios aqu铆 y ahora. Llamar茅 a su .close() m茅todos tan pronto como termine con el trabajo en el bloque try. Si se lanza una excepci贸n mientras estoy en el bloque try, cerrar茅 esos recursos de todos modos.

    Antes de que se introdujera este enfoque, el cierre de recursos se realizaba manualmente, como se ve en el c贸digo anterior. Esto era esencialmente c贸digo repetitivo, y las bases de c贸digo estaban llenas de ellos, lo que reduc铆a la legibilidad y dificultaba su mantenimiento.

    los catch y finally parte del trabajo de prueba con recursos como se esperaba, con catch bloques que manejan sus respectivas excepciones y el finally bloque ejecutado independientemente de si hubo una excepci贸n o no. La 煤nica diferencia son las excepciones suprimidas, que se explican al final de este art铆culo.

    Nota: Desde Java 9, no es necesario declarar los recursos dentro de la declaraci贸n try-with-resources. En su lugar, podemos hacer algo como esto:

    BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
    try (writer) {
        writer.write(str); // do something with the file we've opened
    }
    catch(IOException e) {
        // handle the exception
    }
    

    M煤ltiples recursos

    Otro buen aspecto de try-with-resources es la facilidad para agregar / eliminar recursos que estamos usando y tener la seguridad de que se cerrar谩n una vez que hayamos terminado.

    Si quisi茅ramos trabajar con varios archivos, abrir铆amos los archivos en el try() declaraci贸n y sep谩relos con un punto y coma:

    try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
        Scanner scanner = new Scanner(System.in)) {
    if (scanner.hasNextLine())
        writer.write(scanner.nextLine());
    }
    catch(IOException e) {
        // handle the exception
    }
    

    Java luego se encarga de llamar .close() en todos los recursos que hemos abierto en try().

    Nota: Est谩n cerrados en orden de declaraci贸n inverso, lo que significa que, en nuestro ejemplo, scanner estar谩 cerrado antes del writer.

    Clases admitidas

    Todos los recursos declarados en try() debe implementar el AutoCloseable interfaz. Suelen tratarse de varios tipos de escritores, lectores, sockets, flujos de entrada o salida, etc. Todo lo que necesite escribir resource.close() una vez que haya terminado de trabajar con 茅l.

    Esto, por supuesto, incluye objetos definidos por el usuario que implementan la AutoClosable interfaz. Sin embargo, rara vez se encontrar谩 con una situaci贸n en la que desee escribir sus propios recursos.

    En caso de que eso suceda, debe implementar el AutoCloseable o Closeable (solo para preservar la compatibilidad con versiones anteriores, prefiera AutoCloseable) interfaz y anular la .close() m茅todo:

    public class MyResource implements AutoCloseable {
        @Override
        public void close() throws Exception {
            // close your resource in the appropriate way
        }
    }
    

    Manejo de excepciones

    Si se lanza una excepci贸n desde dentro de un bloque de prueba con recursos de Java, cualquier recurso abierto entre par茅ntesis de try el bloque a煤n se cerrar谩 autom谩ticamente.

    Como se mencion贸 anteriormente, try-with-resources funciona igual que try-catch-finalmente, excepto con una peque帽a adici贸n. La adici贸n se llama excepciones suprimidas. Es no Es necesario comprender las excepciones suprimidas para poder usar try-with-resources, pero leer sobre ellas puede ser 煤til para depurar cuando nada m谩s parece funcionar.

    Imagina una situaci贸n:

    • Por alguna raz贸n, se produce una excepci贸n en el bloque try-with-resources
    • Java detiene la ejecuci贸n en el bloque try-with-resources y llama .close() sobre todos los recursos declarados en try()
    • Uno de los .close() los m茅todos arrojan una excepci贸n
    • 驴Qu茅 excepci贸n ser铆a la catch bloquear “captura”?

    Esta situaci贸n nos introduce en las excepciones suprimidas antes mencionadas. Una excepci贸n suprimida es una excepci贸n que de alguna manera se ignora cuando se lanza dentro del bloque final impl铆cito de un bloque try-with-resources, en el caso de que se lanza una excepci贸n desde el try bloque tambi茅n.

    Esas excepciones son excepciones que ocurren en el .close() m茅todos y se accede a ellos de forma diferente a las excepciones “normales”.

    Es importante comprender que el orden de ejecuci贸n es:

    • bloque try-with-resources
    • impl铆cito finalmente
    • catch block (si se lanz贸 una excepci贸n [1] y / o [2])
    • (expl铆cito) finalmente

    Por ejemplo, aqu铆 hay un recurso que no hace m谩s que lanzar excepciones:

    public static class MyResource implements AutoCloseable {
        // method throws RuntimeException
        public void doSomething() {
            throw new RuntimeException("From the doSomething method");
        }
    
        // we'll override close so that it throws an exception in the implicit finally block of try-with-resources (when it attempts to close our resource)
        @Override
        public void close() throws Exception {
            throw new ArithmeticException("I can throw whatever I want, you can't stop me.");
        }
    }
    
    public static void main(String[] arguments) throws Exception {
        // declare our resource in try
        try (MyResource resource = new MyResource()) {
            resource.doSomething();
        }
        catch (Exception e) {
            System.out.println("Regular exception: " + e.toString());
    
            // getting the array of suppressed exceptions, and its length
            Throwable[] suppressedExceptions = e.getSuppressed();
            int n = suppressedExceptions.length;
    
            if (n > 0) {
                System.out.println("We've found " + n + " suppressed exceptions:");
                for (Throwable exception : suppressedExceptions) {
                    System.out.println(exception.toString());
                }
            }
        }
    }
    

    Este c贸digo se puede ejecutar. Puede usarlo para experimentar con el uso de m煤ltiples MyResource objetos o ver lo que sucede cuando try-with-resources no lanza una excepci贸n, pero .close() hace.

    Insinuaci贸n: De repente, las excepciones lanzadas al cerrar los recursos comienzan a ser importantes.

    Es importante tener en cuenta que, en caso de que un recurso arroje una excepci贸n cuando intente cerrarlo, cualquier otro recurso abierto dentro del mismo bloque try-with-resources seguir谩 cerrado.

    Otro hecho a tener en cuenta es que en una situaci贸n en la que el try block no lanza una excepci贸n, y donde hay m煤ltiples excepciones lanzadas al intentar .close() los recursos utilizados, el primero La excepci贸n se propagar谩 por la pila de llamadas, mientras que las dem谩s se suprimir谩n.

    Como puede ver en el c贸digo, puede obtener la lista de todas las excepciones suprimidas accediendo al Throwable matriz devuelta por Throwable.getSuppressed().

    Recuerde, solo se puede lanzar una 煤nica excepci贸n dentro del bloque try. Tan pronto como se lanza una excepci贸n, se sale del c贸digo del bloque try y Java intenta cerrar los recursos.

    Conclusi贸n

    try-with-resources debe usarse en lugar del try-catch-finalmente habitual siempre que sea posible. Es f谩cil olvidarse de cerrar uno de sus recursos despu茅s de codificar durante horas u olvidarse de cerrar un recurso que acaba de agregar a su programa despu茅s de una explosi贸n aleatoria de inspiraci贸n.

    El c贸digo es m谩s legible, m谩s f谩cil de cambiar y mantener y, por lo general, m谩s corto.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *