Java 42: try-with-resources & AutoCloseable
easy⏱ 5 mincoursejava
La construcción
try (var r = open()) { use(r); } — cualquier recurso declarado en los paréntesis que implemente AutoCloseable (o Closeable, que estrecha close() para lanzar IOException) se cierra automáticamente al salir del bloque, normal o excepcionalmente. Varios recursos se separan con ; y se cierran en orden inverso de declaración.
try (var in = new FileInputStream("a");
var out = new FileOutputStream("b")) {
in.transferTo(out);
} // out.close() then in.close() — reverse order, guaranteed
Excepciones suprimidas
Si el cuerpo del try lanza y un close() también lanza, la excepción del cuerpo gana (se propaga) y la de close() queda suprimida — adjunta vía Throwable.addSuppressed(...) y accesible con getSuppressed(). Es lo opuesto al viejo idiom de finally, donde un fallo de close() enmascaraba el error real. try-with-resources nunca pierde la excepción primaria.
Recursos effectively-final (Java 9)
Java 9 permite referenciar una variable ya declarada effectively final en la lista de recursos: try (existing) { ... }. El recurso ya no tiene que declararse dentro de los paréntesis — útil cuando vino de otra parte pero aún quieres cierre garantizado.
Construye un trazador de cierre
Implementa Resource con close() que apile su nombre en un log compartido closed[]. Envuélvelo en un helper tryWith([a, b, c], body) que los cierre en orden inverso dentro de un finally, aunque body lance. Luego haz que el close() de un recurso lance y que el cuerpo también lance — recoge el error del cuerpo como primario y el de cierre en una lista suppressed. Verifica que el orden de cierre sea c, b, a.
Implementa AutoCloseable para tus propios handles
Cualquier wrapper sobre un socket, lock, transacción o archivo temporal debería implementar AutoCloseable para que quien llama obtenga try-with-resources gratis. Haz close() idempotente (seguro de llamar dos veces) y evita lanzar desde él cuando puedas — un close() que lanza complica cada call site.
Quiz: orden de cierre con dos recursos
try (var a = open(); var b = open()) — ¿en qué orden se cierran? b primero, luego a — inverso a la adquisición, como constructores/destructores anidados. Importa cuando b depende de a (p. ej. un buffered writer envolviendo un file stream): el dependiente debe cerrar antes que aquello de lo que depende.