La sintaxis de prueba con recursos de Java 7 (también conocida como bloque ARM ( Gestión automática de recursos )) es agradable, corta y directa cuando se usa solo un AutoCloseable
recurso. Sin embargo, no estoy seguro de lo que es el idioma correcto cuando necesito para declarar múltiples recursos que son dependientes entre sí, por ejemplo, un FileWriter
y una BufferedWriter
que lo envuelve. Por supuesto, esta pregunta se refiere a cualquier caso cuando AutoCloseable
se envuelven algunos recursos, no solo estas dos clases específicas.
Se me ocurrieron las tres alternativas siguientes:
1)
El lenguaje ingenuo que he visto es declarar solo el contenedor de nivel superior en la variable administrada por ARM:
static void printToFile1(String text, File file) {
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Esto es bueno y corto, pero está roto. Debido a que el subyacente FileWriter
no se declara en una variable, nunca se cerrará directamente en el finally
bloque generado . Se cerrará solo a través del close
método de envoltura BufferedWriter
. El problema es que si se lanza una excepción desde el bw
constructor, close
no se llamará y, por lo tanto, el subyacente FileWriter
no se cerrará .
2)
static void printToFile2(String text, File file) {
try (FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw)) {
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Aquí, tanto el recurso subyacente como el envoltorio se declaran en las variables administradas por ARM, por lo que ambos se cerrarán, pero el subyacente fw.close()
se llamará dos veces : no solo directamente, sino también a través del ajuste bw.close()
.
Esto no debería ser un problema para estas dos clases específicas que ambas implementan Closeable
(que es un subtipo de AutoCloseable
), cuyo contrato establece que close
se permiten múltiples llamadas a :
Cierra esta secuencia y libera todos los recursos del sistema asociados a ella. Si la secuencia ya está cerrada, invocar este método no tiene ningún efecto.
Sin embargo, en un caso general, puedo tener recursos que se implementan solo AutoCloseable
(y no Closeable
), lo que no garantiza que close
se pueda llamar varias veces:
Tenga en cuenta que, a diferencia del método de cierre de java.io.Closeable, no es necesario que este método de cierre sea idempotente. En otras palabras, llamar a este método de cierre más de una vez puede tener algún efecto secundario visible, a diferencia de Closeable.close, que se requiere que no tenga efecto si se llama más de una vez. Sin embargo, se recomienda encarecidamente a los implementadores de esta interfaz que hagan idempotentes sus métodos cercanos.
3)
static void printToFile3(String text, File file) {
try (FileWriter fw = new FileWriter(file)) {
BufferedWriter bw = new BufferedWriter(fw);
bw.write(text);
} catch (IOException ex) {
// handle ex
}
}
Esta versión debería ser teóricamente correcta, porque solo fw
representa un recurso real que necesita ser limpiado. El bw
mismo no contiene ningún recurso, solo delega en el fw
, por lo que debería ser suficiente para cerrar solo el subyacente fw
.
Por otro lado, la sintaxis es un poco irregular y, además, Eclipse emite una advertencia, que creo que es una falsa alarma, pero sigue siendo una advertencia con la que uno tiene que lidiar:
Fuga de recursos: 'bw' nunca se cierra
Entonces, ¿qué enfoque elegir? ¿O me he perdido algún otro idioma que es el correcto ?
public BufferedWriter(Writer out, int sz)
puede lanzar un IllegalArgumentException
. Además, puedo extender BufferedWriter con una clase que arrojaría algo de su constructor o crearía cualquier contenedor personalizado que necesite.
BufferedWriter
constructor puede lanzar fácilmente una excepción. OutOfMemoryError
es probablemente el más común, ya que asigna una buena cantidad de memoria para el búfer (aunque puede indicar que desea reiniciar todo el proceso). / Necesitas flush
tu BufferedWriter
si no cierras y quieres conservar el contenido (generalmente solo el caso sin excepción). FileWriter
recoge lo que sea que sea la codificación de archivo "predeterminada"; es mejor ser explícito.