java - try - Cierre varios recursos con AutoCloseable(prueba con recursos)
try with resources jdbc (4)
Sé que el recurso que pasa con una prueba se cerrará automáticamente si el recurso tiene AutoCloseable implementado. Hasta aquí todo bien. Pero, ¿qué hago cuando tengo varios recursos que quiero cerrar automáticamente? Ejemplo con enchufes;
try (Socket socket = new Socket()) {
input = new DataInputStream(socket.getInputStream());
output = new DataOutputStream(socket.getOutputStream());
} catch (IOException e) {
}
Entonces sé que el socket se cerrará correctamente, porque se pasa como un parámetro en el intento, pero ¿cómo se deben cerrar correctamente la entrada y la salida?
Además de las respuestas anteriores, esta es la mejora agregada en Java 9.
Java 9 probar con recursos hace una forma mejorada de escribir código. Ahora puede declarar la variable fuera del bloque try y usarla dentro del bloque try directamente. Debido a esto obtendrá los siguientes beneficios.
-
Los recursos que declaró fuera de prueba (que es efectivamente final o final) pueden cerrarse automáticamente mediante la administración automática de recursos simplemente agregándolos en el bloque de prueba.
- No es necesario volver a hacer referencia a objetos declarados fuera del bloque de prueba ni cerrarlos manualmente, como debemos hacer en Java 7.
- También ayuda a escribir código limpio.
try-with-resource podemos escribir así en Java 9.
public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (dbCon; ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
while (rs.next()) {
System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
}
} catch (SQLException e) {
System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
}
}
Aquí la gestión automática de recursos cerrará automáticamente los objetos dbCon y rs.
Para una mejor comprensión de la lista de casos de uso definidos anteriormente, busque algún código Java 7.
Ejemplo 1:
public void loadDataFromDB() throws SQLException {
Connection dbCon = DriverManager.getConnection("url", "user", "password");
try (ResultSet rs = dbCon.createStatement().executeQuery("select * from emp")) {
while (rs.next()) {
System.out.println("In loadDataFromDB() =====>>>>>>>>>>>> " + rs.getString(1));
}
} catch (SQLException e) {
System.out.println("Exception occurs while reading the data from DB ->" + e.getMessage());
} finally {
if (null != dbCon)
dbCon.close();
}
}
Ejemplo 2
// BufferedReader is declared outside try() block
BufferedReader br = new BufferedReader(new FileReader("C://readfile/input.txt"));
try (BufferedReader inBr = br) {
// ...
}
} catch (IOException e) {
// ...
}
En las muestras anteriores, puede ver si el objeto está fuera de prueba, entonces debemos cerrarlo manualmente o volver a consultarlo. También en el caso de varios objetos en el bloque try, se ve desordenado e incluso si declaras try interno, entonces no puedes usar el bloque try externo.
Las respuestas anteriores son geniales, pero hay algunos casos en que probar con recursos no ayuda.
Eche un vistazo a este ejemplo de código:
private static byte[] getFileBytes(Collection<String> fileContent) throws CustomServiceException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(baos))) {
for (String fileLine : fileContent) {
writer.append(fileLine);
writer.newLine();
}
}
return baos.toByteArray();
} catch (IOException e) {
throw new CustomServiceException(SC_INTERNAL_SERVER_ERROR, "Unable to serialize file data.");
}
}
En este ejemplo, no puede usar el bloque try-with-resources porque el escritor tiene que vaciar el búfer de salida a la secuencia de caracteres subyacente, por lo que colocar el escritor en el bloque try-with-resources no hará el truco y el método devolverá una matriz vacía .
No se preocupe, las cosas "simplemente funcionarán". De la documentación de Socket :
Cerrar este socket también cerrará InputStream y OutputStream del socket.
Entiendo su preocupación por no llamar explícitamente a
close()
en los objetos de entrada y salida y, de hecho, generalmente es mejor asegurarse de que todos los recursos sean administrados automáticamente por el bloque
try-with-resources
, de esta manera:
try (Socket socket = new Socket();
InputStream input = new DataInputStream(socket.getInputStream());
OutputStream output = new DataOutputStream(socket.getOutputStream());) {
} catch (IOException e) {
}
Esto tendría el efecto de que el objeto de socket se "cerraría varias veces", pero eso no debería causar ningún daño (esta es una de las razones por las que generalmente se aconseja que todas las implementaciones de
close()
se hagan idempotentes).
Probar con recursos se puede utilizar con múltiples recursos declarándolos todos entre paréntesis. Ver la documentation
Extracto de código relevante de la documentación vinculada:
public static void writeToFileZipFileContents(String zipFileName,
String outputFileName)
throws java.io.IOException {
java.nio.charset.Charset charset =
java.nio.charset.StandardCharsets.US_ASCII;
java.nio.file.Path outputFilePath =
java.nio.file.Paths.get(outputFileName);
// Open zip file and create output file with
// try-with-resources statement
try (
java.util.zip.ZipFile zf =
new java.util.zip.ZipFile(zipFileName);
java.io.BufferedWriter writer =
java.nio.file.Files.newBufferedWriter(outputFilePath, charset)
) {
// Enumerate each entry
for (java.util.Enumeration entries =
zf.entries(); entries.hasMoreElements();) {
// Get the entry name and write it to the output file
String newLine = System.getProperty("line.separator");
String zipEntryName =
((java.util.zip.ZipEntry)entries.nextElement()).getName()
newLine;
writer.write(zipEntryName, 0, zipEntryName.length());
}
}
}
Si sus objetos no implementan
AutoClosable
(
DataInputStream
sí) o deben declararse antes de probar con recursos, entonces el lugar apropiado para cerrarlos es
finally
un bloque, también mencionado en la documentación vinculada.