Question 10 · Section 7

What are the requirements for resources in try-with-resources?

The resource must implement the java.lang.AutoCloseable interface. Without this, it cannot be used in try-with-resources.

Language versions: English Russian Ukrainian

Junior Level

Main requirement

The resource must implement the java.lang.AutoCloseable interface. Without this, it cannot be used in try-with-resources.

// Works - FileInputStream implements AutoCloseable
try (FileInputStream fis = new FileInputStream("file.txt")) {
    fis.read();
}

// Won't compile - String does not implement AutoCloseable
try (String s = "hello") { } // Compilation error

Which classes implement AutoCloseable

  • All InputStream / OutputStream - files, network
  • All Reader / Writer - text
  • Connection, Statement, ResultSet - database
  • Scanner, Formatter - utilities

Multiple resources

try (FileInputStream fis = new FileInputStream("in.txt");
     FileOutputStream fos = new FileOutputStream("out.txt")) {
    // Both will be closed automatically
}

Java 9+ - external variables

FileInputStream fis = createStream();
try (fis) { // fis must be effectively final
    fis.read();
}

When NOT to put resource in try-with-resources

  1. Container-managed resource (Spring @Bean) - framework closes it itself
  2. Pooled connection (HikariCP) - pool manages lifecycle for you
  3. Need to pass resource further - return from method, TWR will close before return

Middle Level

AutoCloseable vs Closeable

AutoCloseable (Java 7, java.lang):

  • void close() throws Exception
  • Universal - for any resources

Closeable (Java 5, java.io):

  • void close() throws IOException
  • Only for I/O
  • Inherits AutoCloseable

Either one works for try-with-resources.

Leak risk during initialization

// SAFE - if B fails, A will close
try (A a = new A(); B b = new B(a)) { }

// DANGEROUS - if B fails, A leaks
try (B b = new B(new A())) { }
// A is created but try has no reference to it
// Leak analysis: new A() created object. new B(a) threw exception.
// A is created, but the variable in TWR is B. TWR has no reference to A,
// so close() for A won't be called. Solution:
// try (A a = new A(); B b = new B(a)) { ... }

Idempotency of close()

The close() method must be idempotent - repeated call should not throw an exception.

Idempotency - property of an operation: repeated call produces the same result as the first. close() must be idempotent: first call closes resource, second - does nothing (doesn’t throw).

public void close() {
    if (closed.compareAndSet(false, true)) {
        // actual resource release
    }
}

Variable requirements (Java 9+)

Resource must be final or effectively final. Compiler creates a local copy of the reference - this guarantees that if another thread changes the external variable, TWR still closes the original object.

effectively final = variable doesn’t change after initialization, even if the final keyword is not written. The compiler sees that you don’t change the variable and allows using it in TWR.


Senior Level

Under the Hood: compiler creates a copy

When using an external variable in try(resource), the compiler creates a local copy of the reference. This guarantees thread-safe closing.

Throwing exceptions from close()

If close() throws an exception:

  • If there were no errors in try - exception from close() becomes the main one
  • If there was already an exception in try - from close() is added to suppressed

Interrupted close

In network operations, close() may block. Set timeouts, otherwise the thread will “hang” at the resource closing stage.

Object Allocation and GC

try-with-resources creates objects. When opening/closing thousands of resources per second, this creates pressure on GC (Young Generation). Use resource pools (HikariCP for DB), which implement AutoCloseable but instead of closing, return the object to the pool.

Edge Cases

  • Resource didn’t open - if constructor threw, TWR won’t try to close (nothing to close)
  • Partial initialization - if constructor opened native resource but failed before returning - leak. Keep constructors light.

Diagnostics

  • Resource Leak Detection - IDE highlights AutoCloseable classes not used in TWR. Don’t ignore.
  • jstack analysis - many threads in BLOCKED / WAITING in close() - check for deadlocks between resources.

Interview Cheat Sheet

Must know:

  • Resource must implement java.lang.AutoCloseable
  • AutoCloseable (Java 7, java.lang) - close() throws Exception; Closeable (Java 5, java.io) - close() throws IOException
  • close() method must be idempotent - repeated call doesn’t throw
  • Declare resources separately: try (A a = new A(); B b = new B(a)) - otherwise leak
  • Java 9+: external variables must be effectively final
  • Compiler creates local copy of reference - guarantees thread-safe closing
  • If close() throws when there’s an error in try - added to suppressed
  • Resource pools (HikariCP) implement AutoCloseable but return object to pool, not close

Frequent follow-up questions:

  • What is the difference between AutoCloseable and Closeable? - AutoCloseable is more universal (throws Exception), Closeable only for I/O (throws IOException)
  • What is idempotency of close()? - First call closes resource, second - does nothing
  • Why is nested resource creation dangerous? - new B(new A()) - if B fails, TWR has no reference to A, it leaks
  • What happens on mass open/close of resources? - GC pressure; use resource pools

Red flags (NOT to say):

  • “Close() can throw exception every time” - must be idempotent
  • “I don’t declare resources separately to make it shorter” - this causes leaks
  • “TWR closes pooled connection” - pool manages lifecycle itself, return != close

Related topics:

  • [[What is try-with-resources]]
  • [[What is the AutoCloseable interface]]
  • [[What is the difference between AutoCloseable and Closeable]]
  • [[What are suppressed exceptions]]
  • [[Which exceptions must be handled]]