Working with files, streams, database connections, sockets, and other resources introduces an important responsibility: the resource must be closed when you are finished with it. Forgetting to close a resource can lead to resource leaks, locked files, exhausted connections, and unstable applications.
Java's try-with-resources statement provides a clean solution. It automatically closes resources after the try block finishes, whether the block completes normally or an exception occurs.
Why Try-with-Resources Exists
Before try-with-resources was introduced, developers commonly used a finally block to close resources manually.
FileReader reader = null;
try {
reader = new FileReader("data.txt");
int value = reader.read();
System.out.println(value);
} catch (IOException e) {
System.out.println("Reading failed.");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
System.out.println("Closing failed.");
}
}
}
This works, but notice how much code is required just to guarantee that the reader is closed. The cleanup logic can also become complicated when several resources are involved.
Try-with-resources moves that responsibility into the language itself.
Basic Syntax
try (ResourceType resource = createResource()) {
// Use the resource
} catch (ExceptionType e) {
// Handle exception
}
The resource is declared inside the parentheses after try. Java automatically closes it when execution leaves the try block.
Simple File Example
try (FileReader reader = new FileReader("data.txt")) {
int value = reader.read();
System.out.println(value);
} catch (IOException e) {
System.out.println("Unable to read file.");
}
There is no explicit finally block and no manual close() call. Java handles the cleanup automatically.
Remember: A resource declared in a try-with-resources statement is automatically closed when the try block finishes.
What Is a Resource?
A resource is an object that implements the AutoCloseable interface. Java's Closeable interface also qualifies because it extends AutoCloseable.
public interface AutoCloseable {
void close() throws Exception;
}
Classes such as file readers, input streams, output streams, database resources, and many other resource-managing classes implement one of these interfaces.
The AutoCloseable Contract
The key idea behind try-with-resources is simple: Java knows that an object can be closed because it implements AutoCloseable.
When the try block finishes, Java automatically invokes the resource's close() method.
Understanding the Execution Flow
try (FileReader reader = new FileReader("data.txt")) {
System.out.println("Reading file...");
}
Conceptually, Java performs the following sequence:
- Create the resource.
- Execute the try block.
- Close the resource automatically.
- Propagate or handle any exception that occurs.
The important detail is that closing happens even when the try block exits because of an exception.
Try-with-Resources with finally
Try-with-resources can be combined with a finally block when additional cleanup or logic is required.
try (FileReader reader = new FileReader("data.txt")) {
System.out.println(reader.read());
} catch (IOException e) {
System.out.println("Read failed.");
} finally {
System.out.println("Operation finished.");
}
The resource is closed automatically before the finally block executes.
Multiple Resources
One of the biggest advantages of try-with-resources is the ability to manage multiple resources in the same statement.
try (
FileReader reader = new FileReader("input.txt");
FileWriter writer = new FileWriter("output.txt")
) {
int value;
while ((value = reader.read()) != -1) {
writer.write(value);
}
} catch (IOException e) {
System.out.println("File operation failed.");
}
Both resources are automatically closed. You do not need separate finally blocks for each resource.
Order of Closing Multiple Resources
When multiple resources are declared, Java closes them in the reverse order of their declaration.
try (
ResourceA a = new ResourceA();
ResourceB b = new ResourceB();
ResourceC c = new ResourceC()
) {
// Work
}
The closing order is:
c.close(); b.close(); a.close();
This reverse-order behavior is useful because later-created resources may depend on resources created earlier.
Important: Resources are closed in reverse declaration order. This is similar to unwinding a stack: the most recently acquired resource is released first.
Creating Your Own AutoCloseable Resource
You can create your own resource type by implementing AutoCloseable.
class DatabaseConnection
implements AutoCloseable {
public void connect() {
System.out.println("Connected.");
}
@Override
public void close() {
System.out.println("Connection closed.");
}
}
Now the class can be used directly with try-with-resources.
try (DatabaseConnection connection =
new DatabaseConnection()) {
connection.connect();
}
When the try block ends, Java automatically calls close().
A Custom Resource in Action
class ResourceDemo
implements AutoCloseable {
public void use() {
System.out.println("Using resource.");
}
@Override
public void close() {
System.out.println("Cleaning resource.");
}
}
public class Main {
public static void main(String[] args) {
try (ResourceDemo resource =
new ResourceDemo()) {
resource.use();
}
}
}
The output will show the resource being used first and then cleaned automatically.
Exception During Resource Creation
A resource can fail even before the try block begins. For example, opening a file may throw an IOException.
try (FileReader reader =
new FileReader("missing.txt")) {
System.out.println(reader.read());
} catch (IOException e) {
System.out.println(
"Could not open or read the file."
);
}
If resource creation fails, the body of the try block does not execute. The exception is handled by the appropriate catch block.
Exception During close()
The close() method itself can throw an exception. Java's try-with-resources mechanism handles this situation carefully.
class MyResource
implements AutoCloseable {
@Override
public void close() throws Exception {
throw new Exception(
"Closing failed."
);
}
}
If closing the resource fails, the exception participates in the normal exception mechanism. When another exception already occurred in the try block, the close exception may become a suppressed exception.
Suppressed Exceptions
Suppose the try block throws one exception and then the resource throws another exception while closing. Java preserves both instead of simply throwing away one of them.
try (MyResource resource = new MyResource()) {
throw new Exception("Main operation failed.");
} catch (Exception e) {
System.out.println(e.getMessage());
for (Throwable suppressed :
e.getSuppressed()) {
System.out.println(
"Suppressed: " + suppressed.getMessage()
);
}
}
The exception from the main operation is normally the primary exception. The exception raised during closing is retained as a suppressed exception.
Remember: Use getSuppressed() when you need to inspect exceptions that occurred while resources were being closed after another exception had already been raised.
Java 9: Existing Resources
Modern Java also allows an effectively final resource variable to be used directly in the try-with-resources statement.
FileReader reader =
new FileReader("data.txt");
try (reader) {
System.out.println(reader.read());
}
The variable is not redeclared inside the parentheses. Java closes the existing resource when the try statement completes.
Effectively Final Resource Variables
A resource referenced directly in the try-with-resources statement must be final or effectively final.
FileReader reader =
new FileReader("data.txt");
try (reader) {
// Valid
}
But repeatedly assigning a new value to the variable prevents it from being effectively final.
FileReader reader =
new FileReader("data.txt");
reader = new FileReader("other.txt");
try (reader) {
// Not valid because reader was reassigned
}
Try-with-Resources vs finally
| Feature | Traditional finally | Try-with-resources |
|---|---|---|
| Resource closing | Manual | Automatic |
| Code size | Usually larger | Usually smaller |
| Multiple resources | Requires additional cleanup logic | Handled naturally |
| Closing failures | Must be handled manually | Integrated with suppressed exceptions |
| Readability | More cleanup code | Clear resource lifecycle |
Common Beginner Mistakes
- Manually calling close() inside the try block when try-with-resources already handles it.
- Assuming every object can be used with try-with-resources without implementing AutoCloseable.
- Ignoring suppressed exceptions when diagnosing complicated resource failures.
- Forgetting that resources close in reverse declaration order.
- Reassigning a resource variable and then expecting it to qualify as an effectively final resource.
- Using a manual finally block when try-with-resources provides a simpler and safer solution.
Best Practices
- Prefer try-with-resources whenever you work with resources that implement AutoCloseable.
- Keep resource acquisition inside the try-with-resources statement when practical.
- Declare dependent resources in the order that allows safe reverse-order closing.
- Do not hide exceptions thrown during resource cleanup.
- Use getSuppressed() when diagnosing multiple failures involving resource cleanup.
- Implement AutoCloseable for custom resources that require deterministic cleanup.
Interview Insights
A common interview question is: "What is try-with-resources?" It is a Java construct that automatically closes resources implementing AutoCloseable after the try block finishes.
Another common question is: "In what order are multiple resources closed?" They are closed in reverse order of declaration.
Interviewers may also ask: "What happens if both the try block and close() throw exceptions?" The exception from the try block normally remains the primary exception, while the exception from close() is retained as a suppressed exception.
A useful interview distinction is also worth remembering: try-with-resources is not merely a shorter finally block. It provides a structured resource-management mechanism with defined closing behavior and support for suppressed exceptions.
Quick Revision
| Concept | Key Idea |
|---|---|
| Try-with-resources | Automatically closes resources when the try statement finishes. |
| AutoCloseable | Interface that allows an object to participate in automatic resource closing. |
| close() | Method automatically invoked when the resource is released. |
| Multiple resources | Can be declared in one try statement and close in reverse order. |
| Suppressed exception | An exception raised during resource closing while another exception is already active. |
| Java 9 improvement | Existing final or effectively final resources can be referenced directly in try-with-resources. |
Try-with-resources turns resource cleanup from a repetitive manual task into a reliable part of the language's control flow. By automatically closing AutoCloseable resources and preserving cleanup failures as suppressed exceptions, it makes Java programs shorter, safer, and easier to maintain. With this chapter, the complete Exception Handling topic list has been covered.
