Week 108 — What is a `try`-with-resources statement and what is it useful for?

Question of the Week #108
What is a try-with-resources statement and what is it useful for?
7 Replies
CrimsonDragon1
Many resources like files, database connections or network sockets should be closed as soon as they are no longer needed. To do this, one could naively implement that similar to the following:
//DON'T DO THIS - this is risky
BufferedWriter bw = Files.newBufferedWriter(Path.of("someFile.txt"));

bw.write("Hello World\n");

//close the BufferedWriter since it's no longer needed
bw.close();
//DON'T DO THIS - this is risky
BufferedWriter bw = Files.newBufferedWriter(Path.of("someFile.txt"));

bw.write("Hello World\n");

//close the BufferedWriter since it's no longer needed
bw.close();
However, if an exception occurs, the close() method isn't called so the resource would stay open. To resolve this problem, one could close the BufferedWriter in a finally block:
//create BufferedWriter immediately before try block
//there must be nothing between the creation of the resource and the start of the try block
BufferedWriter bw = Files.newBufferedWriter(Path.of("someFile.txt"));
try {
bw.write("Hello World\n");
} finally {
//the finally-block is guranteed to be executed when the try-block ends, with or without an exception
// (assuming the JVM doesn't terminate abruptly and the current thread isn't a daemon-thread with the application stopping)
bw.close();
}
//create BufferedWriter immediately before try block
//there must be nothing between the creation of the resource and the start of the try block
BufferedWriter bw = Files.newBufferedWriter(Path.of("someFile.txt"));
try {
bw.write("Hello World\n");
} finally {
//the finally-block is guranteed to be executed when the try-block ends, with or without an exception
// (assuming the JVM doesn't terminate abruptly and the current thread isn't a daemon-thread with the application stopping)
bw.close();
}
CrimsonDragon1
With the finally block ensuring that close() is called, this seems like a good solution. However, this can become inconvenient when operating with multiple resources:
//This is one correct way to do it but it suffers from readability and maintainability issues
//DON'T DO THIS - there are better alternatives
InputStream is;
OutputStream os;
is = Files.newInputStream(Path.of("input.dat"));
try {
os = Files.newOutputStream(Path.of("output.dat"));

//do work
is.transferTo(os);
} finally {
try{
// we first close one of the resource (if that resource was nullable, we would need a null check)
is.close();
} finally {
// even if closing the InputStream fails for some reason, we still want the OutputStream to be closed
// if the creation of os fails, it could be null hence we need a null check
if(os != null) {
//finally close the other resource
os.close();
}
}
}
//This is one correct way to do it but it suffers from readability and maintainability issues
//DON'T DO THIS - there are better alternatives
InputStream is;
OutputStream os;
is = Files.newInputStream(Path.of("input.dat"));
try {
os = Files.newOutputStream(Path.of("output.dat"));

//do work
is.transferTo(os);
} finally {
try{
// we first close one of the resource (if that resource was nullable, we would need a null check)
is.close();
} finally {
// even if closing the InputStream fails for some reason, we still want the OutputStream to be closed
// if the creation of os fails, it could be null hence we need a null check
if(os != null) {
//finally close the other resource
os.close();
}
}
}
This is annoying to write and small mistakes can result in the resources not being closed correctly. Furthermore, if an exception both within the try block occurs in any of the close() methods (which could happen for all sorts of reasons, for example a network connection going failing when writing/closing it), that exception would replace the original exception.
📖 Sample answer from dan1st
CrimsonDragon1
try-with-resources statement in Java makes sure that resources like files connections are automatically closed after use, which simplifies resource management and reduces the risk of leaks.
Submission from thehsb
CrimsonDragon1
All I know for now as a beginner is that try-with-resources is used for I/O functions that will be automaticaly closed after we end our work with them. Instead of writring try-catch with finally where in final part we will close the connection , it will be done automaticaly by the language
Submission from sett9824
CrimsonDragon1
A try with a resource is basicly a way to replace the "finaly" statement because it will automaticly close your in or out streams. example:
try(FileReader reader = new Filereader(…)){

}
try(FileReader reader = new Filereader(…)){

}
Normaly:
try(
FileReader reader = ...;
FileWriter writer = ...;
)
{

} finaly {
reader.close();
}
try(
FileReader reader = ...;
FileWriter writer = ...;
)
{

} finaly {
reader.close();
}
You can also add multiple of them with a ';' to split them.
Submission from ufo.dev
CrimsonDragon1
try-with-resources is a mechanism to simplify resource creation and cleanup. For instance, working with an input stream in a "traditional" try block would look like this:
FileInputStream fis = null;
try {
fis = new FileInputStream("to/some/file");
// Read from the stream...
} catch (IOException e) {
// Handle exception
} finally {
if (fis != null) {
// Nested try is necessary because close() can throw an exception
try {
fis.close();
} catch (IOException e) {
// ignore or handle
}
}
}
FileInputStream fis = null;
try {
fis = new FileInputStream("to/some/file");
// Read from the stream...
} catch (IOException e) {
// Handle exception
} finally {
if (fis != null) {
// Nested try is necessary because close() can throw an exception
try {
fis.close();
} catch (IOException e) {
// ignore or handle
}
}
}
Contrast this with a similar try-with-resources statement, which removes a lot of the boilerplate code:
try (FileInputStream fis = new FileInputStream("to/some/file")) {
// Read from the stream...
} catch (IOException e) {
// Handle exception
}
try (FileInputStream fis = new FileInputStream("to/some/file")) {
// Read from the stream...
} catch (IOException e) {
// Handle exception
}
In this example, the finally block is not needed, since fis will be closed automatically once the try block completes (whether it finishes successfully or an exception is thrown).
CrimsonDragon1
Some other items of note about try-with-resources: - Any class that implements java.lang.AutoCloseable can be used inside the try() block - Multiple resources can be instantiated inside try(), separated with a semicolon, e.g. try (InputStream is = ...; OutputStream os = ...) - It is valid to have a try-with-resources statement without any catch or finally blocks, as long as the method propagates any potential exceptions via the throws clause, and no additional cleanup is needed beyond the managed resources - The resources will have been closed before any exception handler or finally block is run - If the try block generates an exception, then any exceptions generated when auto-closing the resource will be suppressed, and the exception from the try block will be thrown. The suppressed exceptions can be retrieved with the Throwable::getSuppressed method.
⭐ Submission from dangerously_casual

Did you find this page helpful?