skip to content

Explain the AutoCloseable and Closeable interfaces and the contract of close().

level: middleimportance: must knowfreq 60%

answer

  1. AutoCloseable: java.lang, close() throws Exception
  2. Closeable: java.io, close() throws IOException, extends AutoCloseable
  3. Closeable.close() is idempotent; AutoCloseable not required to be
  4. narrow the throws clause when cleanup cannot fail
  5. Closeable predates Java 7, retrofitted under AutoCloseable

basics

~20 s

AutoCloseable is an interface with one method, close(), that releases a resource. Closeable is a more specific version for I/O. A class implementing either can be used in try-with-resources, and close() should free whatever the object is holding.

solid answer

~40 s

AutoCloseable (java.lang, since Java 7) is the base interface for anything usable in try-with-resources; it declares a single method, void close() throws Exception. Closeable (java.io, since Java 5) is a subinterface whose close() is narrowed to throw IOException and is documented to be idempotent. The general AutoCloseable contract is that close() releases the underlying resource; it does not require idempotency, so calling it twice may have undefined effects unless the class promises otherwise (Closeable does). Because close() on AutoCloseable can throw a checked Exception, designers often narrow the throws clause to a more specific type, or none, so callers are not forced to handle a broad Exception. In practice you implement AutoCloseable on any type that owns a resource that must be deterministically released.

code

java · 9 lines
java
// Custom resource: narrow the throws clause (no checked exception)
class Scope implements AutoCloseable {
    Scope() { System.out.println("open"); }
    @Override public void close() { System.out.println("close"); }
}

try (Scope s = new Scope()) {
    System.out.println("work");
} // prints open, work, close

go deeper

for a junior

Knows that implementing AutoCloseable (or Closeable) is what lets a class be used in try-with-resources.

for a middle

Distinguishes AutoCloseable (java.lang, throws Exception) from Closeable (java.io, throws IOException, idempotent) and knows Closeable extends AutoCloseable.

for a senior

Explains the idempotency distinction, the throws-narrowing recommendation, and why Closeable was retrofitted under AutoCloseable.

for a principal

Reasons about API design: choosing the right close() signature for library types, idempotency guarantees, and backward-compat retrofitting of interface hierarchies.

## Two interfaces, one idea The try-with-resources statement works with any object whose type implements one of two interfaces: ### `java.lang.AutoCloseable` (Java 7) ```java public interface AutoCloseable { void close() throws Exception; } ``` This is the **base** contract. A single method, `close()`, which the JVM calls to release whatever the object holds. Its `throws Exception` means an implementation is *allowed* to throw any (even checked) exception from cleanup. ### `java.io.Closeable` (Java 5) ```java public interface Closeable extends AutoCloseable { void close() throws IOException; } ``` `Closeable` predates try-with-resources (it was used by I/O classes) and was retrofitted to **extend** `AutoCloseable` so all existing I/O types instantly became usable as resources. It **narrows** the throws clause to `IOException` (overriding methods may declare fewer/narrower checked exceptions — a normal rule of Java overriding). ## The `close()` contract - **Releases the resource**: after `close()`, the object's underlying file/socket/connection is freed. - **Idempotency**: `AutoCloseable.close()` is *not required* to be idempotent — calling it more than once may misbehave. `Closeable.close()` is explicitly documented to be **idempotent** (a second call has no effect). When you write your own AutoCloseable, making `close()` idempotent is good practice. - **It may throw**: cleanup can fail (e.g. flushing a buffer to a broken socket). The interface allows that. ## Narrowing the throws clause Because `throws Exception` is broad and forces callers to handle a checked `Exception`, the Javadoc *recommends* implementers declare a **more specific** exception, or **no** checked exception at all, when cleanup cannot fail. Example: ```java class MyResource implements AutoCloseable { @Override public void close() { /* no checked exception */ } } ``` Now callers using `MyResource` in try-with-resources are not forced into a broad catch. ## When to implement which - Implement **`Closeable`** when your `close()` naturally fails with an `IOException` (I/O types). - Implement **`AutoCloseable`** for everything else (a lock holder, a transaction scope, a timer), narrowing the throws clause to what actually applies. ## Glossary - **Idempotent**: doing it twice has the same effect as doing it once. - **Checked exception**: an exception the compiler forces you to handle or declare. - **Narrowing throws**: an override may declare a subset/subtype of the parent's declared exceptions. The takeaway: `AutoCloseable` is the general resource contract; `Closeable` is its I/O-specialized, idempotent subtype; both are what makes try-with-resources work.

  • Why was Closeable made to extend AutoCloseable rather than the other way round?
    AutoCloseable was introduced in Java 7 as the broader base so try-with-resources could work with any closeable type. Closeable already existed (Java 5) on I/O classes, so making it a subinterface instantly made all existing I/O types valid resources without changing them.
  • Is it a good idea to make your own close() idempotent?
    Yes. Resources can be closed by try-with-resources and possibly again by other code; an idempotent close() avoids double-free errors. Closeable mandates it, and it is recommended for AutoCloseable implementations too.

saying these in an interview costs you the question

  • Saying AutoCloseable.close() is guaranteed idempotent (only Closeable documents that)
  • Thinking Closeable is the parent of AutoCloseable (it is the reverse)
  • Believing close() may not declare any exception (AutoCloseable allows throws Exception)

context