Definition
- try-with-resources declares resources in the try parentheses:
try (Resource r = new Resource()) { use(r); }. The resource'sclose()method is called automatically when the try block exits. - Multiple resources are closed in reverse declaration order:
try (A a = ...; B b = ...) { }closesbfirst, thena. This respects dependency ordering (inner resources before outer). - Dual-exception handling: if both the try body and
close()throw, the try body's exception is primary (propagated) andclose()'s exception is suppressed (attached viaaddSuppressed()). - Any class implementing
AutoCloseable(or its parentCloseable) works with try-with-resources. - Java 9 allows effectively final variables:
BufferedReader r = ...; try (r) { }without re-declaring in the parentheses.
try-with-resources is like the automatic door at National Bank of India. When you walk out of the vault (try block exits), the door closes automatically, whether you walk out normally, run out because of a fire alarm (exception), or are escorted out (return). You do not need a security guard (finally block) standing there waiting to close it. Multiple doors close in reverse order: the inner vault door first, then the outer security door.
Understanding the Concepts
What is try-with-resources?
try-with-resources (Java 7) is a language feature that automatically closes resources when the try block exits. Any class implementing AutoCloseable can be declared in the try parentheses, and its close() method is called automatically.
package com.bank.demo;
import java.io.BufferedReader;
import java.io.StringReader;
public class TryWithResourcesBasic {
public static void main(String[] args) {
String csvData = "SAV2001,50000\nCUR3001,75000";
// Resource declared in try parentheses: auto-closed on exit
try (BufferedReader reader = new BufferedReader(new StringReader(csvData))) {
String line;
while ((line = reader.readLine()) != null) {
String[] parts = line.split(",");
System.out.println("Account: " + parts[0] + ", Balance: Rs." + parts[1]);
}
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
// reader.close() called automatically here.
// No finally needed. No null check needed.
}
}
Account: SAV2001, Balance: Rs.50000
Account: CUR3001, Balance: Rs.75000
How are multiple resources closed?
Multiple resources are closed in reverse declaration order. This ensures inner (dependent) resources are released before outer resources.
package com.bank.demo;
public class MultipleResourcesDemo {
static class Connection implements AutoCloseable {
Connection() { System.out.println("1. Connection opened"); }
@Override public void close() { System.out.println("3. Connection closed (last)"); }
}
static class Statement implements AutoCloseable {
Statement() { System.out.println("2. Statement created"); }
@Override public void close() { System.out.println("2. Statement closed (second)"); }
}
static class ResultSet implements AutoCloseable {
ResultSet() { System.out.println("3. ResultSet opened"); }
@Override public void close() { System.out.println("1. ResultSet closed (first)"); }
}
public static void main(String[] args) {
System.out.println("=== Opening ===");
try (Connection conn = new Connection();
Statement stmt = new Statement();
ResultSet rs = new ResultSet()) {
System.out.println("\n=== Using resources ===");
System.out.println("Processing query results...\n");
}
System.out.println("\nResources closed in REVERSE order");
}
}
=== Opening ===
1. Connection opened
2. Statement created
3. ResultSet opened
=== Using resources ===
Processing query results...
1. ResultSet closed (first)
2. Statement closed (second)
3. Connection closed (last)
Resources closed in REVERSE order
How does try-with-resources compare to the old finally pattern?
The old pattern requires null checks, nested try-catch for close(), and 10+ lines of boilerplate. try-with-resources does the same in 3 lines.
package com.bank.demo;
import java.io.BufferedReader;
import java.io.StringReader;
public class OldVsNewPattern {
// OLD: verbose finally pattern (12 lines of boilerplate)
public static void oldPattern() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new StringReader("SAV2001,50000"));
System.out.println("Old: " + reader.readLine());
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception e) {
System.out.println("Close failed: " + e.getMessage());
}
}
}
}
// NEW: try-with-resources (4 lines, clean)
public static void newPattern() {
try (BufferedReader reader = new BufferedReader(new StringReader("CUR3001,75000"))) {
System.out.println("New: " + reader.readLine());
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
public static void main(String[] args) {
oldPattern();
newPattern();
}
}
Old: SAV2001,50000
New: CUR3001,75000
How do you create a custom AutoCloseable?
Any class that implements AutoCloseable works with try-with-resources. This is powerful for any acquire-release pattern.
package com.bank.service;
public class DistributedLock implements AutoCloseable {
private final String lockKey;
private boolean acquired;
public DistributedLock(String lockKey) {
this.lockKey = lockKey;
this.acquired = true;
System.out.println("Lock acquired: " + lockKey);
}
public void doWork() {
System.out.println("Working under lock: " + lockKey);
}
@Override
public void close() {
if (acquired) {
acquired = false;
System.out.println("Lock released: " + lockKey);
}
}
public static void main(String[] args) {
// Lock is always released, even if doWork() throws
try (DistributedLock lock = new DistributedLock("SETTLEMENT_BATCH_001")) {
lock.doWork();
}
System.out.println("After try block: lock guaranteed released");
}
}
Lock acquired: SETTLEMENT_BATCH_001
Working under lock: SETTLEMENT_BATCH_001
Lock released: SETTLEMENT_BATCH_001
After try block: lock guaranteed released
What changed in Java 9 for try-with-resources?
Java 9 allows effectively final variables to be used directly in try-with-resources without re-declaring them.
package com.bank.demo;
import java.io.BufferedReader;
import java.io.StringReader;
public class Java9Enhancement {
public static void main(String[] args) throws Exception {
// Java 7-8: must declare resource in try parentheses
// BufferedReader r = new BufferedReader(new StringReader("test"));
// try (r) { } // COMPILE ERROR in Java 7-8
// Java 9+: effectively final variable works
BufferedReader reader = new BufferedReader(new StringReader("FD4001,200000"));
try (reader) { // Valid in Java 9+
System.out.println("Java 9: " + reader.readLine());
}
// reader.close() called automatically
}
}
Java 9: FD4001,200000
What are common mistakes with try-with-resources?
package com.bank.demo;
public class TryWithResourcesMistakes {
static class LeakyResource implements AutoCloseable {
LeakyResource() { System.out.println("Resource opened"); }
@Override public void close() { System.out.println("Resource closed"); }
}
// WRONG: resource declared outside try, no auto-close
public static void wrongOutside() throws Exception {
LeakyResource r = new LeakyResource();
try {
System.out.println("Wrong: resource not in try parentheses");
} finally {
r.close(); // Manual close needed, verbose
}
}
// CORRECT: resource in try parentheses
public static void correctInside() {
try (LeakyResource r = new LeakyResource()) {
System.out.println("Correct: auto-close guaranteed");
}
}
public static void main(String[] args) throws Exception {
wrongOutside();
System.out.println();
correctInside();
}
}
Resource opened
Wrong: resource not in try parentheses
Resource closed
Resource opened
Correct: auto-close guaranteed
Resource closed
What should a senior engineer know?
- AutoCloseable vs Closeable.
CloseableextendsAutoCloseableand restrictsclose()to throwIOException.AutoCloseable.close()can throw anyException. Both work with try-with-resources. - Connection pooling. When using HikariCP or similar pools,
connection.close()returns the connection to the pool rather than physically closing it. try-with-resources still works correctly. - Suppressed exceptions. If multiple resources each fail on close, each failure is added as a separate suppressed exception to the primary. All are visible in the stack trace.
- Spring's JdbcTemplate. Spring manages connections internally, so you do not use try-with-resources for connections obtained through JdbcTemplate. But for raw JDBC, try-with-resources is essential.
What are common interview follow-up questions?
- Can try-with-resources have a catch block? (Yes, catch and finally are both optional additions.)
- Can try-with-resources have no catch or finally? (Yes,
try (Resource r = ...) { }is valid by itself.) - What interface must a resource implement? (AutoCloseable or Closeable.)
- In what order are multiple resources closed? (Reverse declaration order.)
- What happens if close() throws? (It becomes a suppressed exception if try also threw.)
Visual Overview
try (A a = new A(); B b = new B()) {
use(a, b);
}
Execution:
1. Open A
2. Open B
3. Execute try body
4. Close B (reverse order, inner first)
5. Close A (reverse order, outer second)
If try throws + close throws:
┌────────────────────────────────────────┐
│ try body exception = PRIMARY │
│ close() exception = SUPPRESSED │
│ Both visible in stack trace │
│ Access: e.getSuppressed() │
└────────────────────────────────────────┘
Key Takeaway
try-with-resources (Java 7) automatically closes any resource implementing AutoCloseable when the try block exits. You declare the resource in the try parentheses and the JVM calls close() automatically, whether the block completes normally, throws an exception, or returns early. Multiple resources are closed in reverse declaration order, ensuring inner resources are released before outer ones.
The key advantage over the old finally pattern is dual-exception handling. If both the try body and close() throw, the try body's exception is primary and close()'s is suppressed via addSuppressed(). Both are visible in the stack trace. In the old pattern, a throw in finally silently destroyed the try exception.
In the banking service at National Bank of India, Rajesh uses custom AutoCloseable implementations for distributed locks, metric timers, and transaction scopes. try (var lock = new SettlementLock("BATCH-001")) { settle(); } guarantees the lock is released even if settlement throws. Before try-with-resources, developers forgot to release locks in catch blocks, and 100 failed settlements exhausted the lock pool.
Remember one sentence: try-with-resources guarantees resource cleanup by automatically calling close() in reverse order when the try block exits.
---