Question 11 · Section 7

What is the AutoCloseable interface?

AutoCloseable appeared in Java 7 specifically for try-with-resources. Closeable (Java 5) was only for I/O streams. AutoCloseable - in java.lang (no imports needed), so any resou...

Language versions: English Russian Ukrainian

Junior Level

Definition

java.lang.AutoCloseable is an interface with a single close() method that is called automatically on exit from a try-with-resources block.

AutoCloseable appeared in Java 7 specifically for try-with-resources. Closeable (Java 5) was only for I/O streams. AutoCloseable - in java.lang (no imports needed), so any resource can become “closeable”.

public interface AutoCloseable {
    void close() throws Exception;
}

How to use

// FileInputStream implements AutoCloseable
try (FileInputStream fis = new FileInputStream("file.txt")) {
    fis.read();
} // fis.close() is called automatically

Which classes implement it

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

Why it’s needed

So you don’t forget to close resources. Before Java 7, you had to write finally with close() manually.


Middle Level

Why in java.lang?

This is a fundamental interface. It was placed in java.lang so it’s available everywhere without imports - at the level of Runnable or Iterable.

Correct close() implementation

1. Narrowing exception type: The interface declares throws Exception. Override with a more specific type:

public class MyResource implements AutoCloseable {
    @Override
    public void close() throws IOException { // more specific
        // closing
    }
}

Or no throws at all if the method is safe.

2. “Safe Close” pattern: If a resource owns several sub-resources:

public void close() throws Exception {
    try {
        subResource1.close();
    } finally {
        subResource2.close(); // will close even if first failed
    }
}

3. Idempotency: Repeated close() call should not throw an exception.

Garbage Collector and AutoCloseable

AutoCloseable does not replace memory management. A resource (file, socket) is a native OS descriptor. If you don’t call close(), the descriptor “hangs” until GC collects the object.

This leads to “Too many open files” error.


Three approaches to resource management

Mechanism When triggered Guarantee Recommendation
TWR On block exit Guaranteed Primary method
Cleaner When GC decides Fallback Fallback if forgot close()
finalize() When GC decides Unpredictable Deprecated (Java 9)

Senior Level

Under the Hood: native descriptors

A resource is not a Java object, but an OS descriptor. A descriptor is a number (int) that the OS issues when opening a file/socket. Java object is just a wrapper. GC sees the wrapper but not the native resource in OS. Without explicit close(), the descriptor leaks even if GC collected the Java object. GC doesn’t see native resources. Without close() descriptor leaks even if Java object is collected.

Atomic State in multithreaded environments

public class MyResource implements AutoCloseable {
    private final AtomicBoolean closed = new AtomicBoolean(false);

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

Two threads must not close one socket simultaneously - undefined behavior at the native driver level.

Throwing exceptions in constructor

If constructor threw an exception after opening a native resource but before returning the object - leak:

public class MyResource implements AutoCloseable {
    private final NativeHandle handle;

    public MyResource(String path) {
        this.handle = openNative(path); // opened
        if (!validate(path)) {
            throw new IllegalArgumentException(); // handle leaked!
        }
    }
}

Solution: light constructors, heavy opening - under try-with-resources.

Cleaner instead of Finalizer (Java 9+)

finalize() is deprecated. For resource “insurance” use java.lang.ref.Cleaner:

public class MyResource implements AutoCloseable {
    private static final Cleaner cleaner = Cleaner.create();
    private final Cleaner.Cleanable cleanable;

    public MyResource() {
        this.cleanable = cleaner.register(this, () -> {
            // last line of defense - if close() was not called
            System.err.println("Resource not closed properly!");
        });
    }

    public void close() {
        cleanable.clean();
    }
}
// Cleaner is triggered by GC. When there are no more strong references to MyResource,
// GC marks the object for cleanup. Cleaner executes the lambda in a separate thread.
// This is NOT a replacement for TWR - GC may take minutes or even hours.
// Cleaner is insurance if you forgot close().

This is only insurance, not replacing the importance of TWR.

Diagnostics

  • SonarLint Rule - “Resources should be closed”. Checks type hierarchy.
  • jcmd VM.native_memory - native memory monitoring
  • Descriptor leak - a common cause of JVM crash after days of operation

Interview Cheat Sheet

Must know:

  • AutoCloseable appeared in Java 7 specifically for try-with-resources
  • Single method: void close() throws Exception
  • Located in java.lang - available without imports, like Runnable
  • close() must be idempotent (repeated call is safe)
  • GC doesn’t see native descriptors - without close() leak even if object collected
  • Narrow throws Exception to specific type or remove entirely
  • Cleaner (Java 9+) - insurance, but NOT a TWR replacement

Frequent follow-up questions:

  • Why in java.lang, not java.io? - So any class can become closeable without imports, at the Object level
  • What happens if you don’t close a resource? - Native descriptor leak -> “Too many open files” -> JVM crash
  • Can close() throw an exception? - Yes, that’s why in multi-resource TWR exceptions are suppressed
  • How is Cleaner better than finalize()? - Cleaner is more predictable, finalize() deprecated in Java 9

Red flags (NOT to say):

  • “GC closes resources itself” - GC collects Java object, but not native descriptor
  • “AutoCloseable only for I/O” - That’s Closeable; AutoCloseable for any resources
  • “close() doesn’t need to be idempotent” - Javadoc strongly recommends it, repeated call must not fail

Related topics:

  • [[12. What is the difference between AutoCloseable and Closeable]]
  • [[9. What is try-with-resources]]
  • [[10. What are the requirements for resources in try-with-resources]]
  • [[18. What is exception wrapping (wrapping)]]
  • [[22. What happens if an exception also occurs in the finally block]]