Resources and try-with-resources

Basic Java
≈ 3 min read

IO objects often own system resources

A file stream is not just an ordinary object in the heap. Behind it there may be a file descriptor, a socket, a channel, or another operating-system resource. The garbage collector manages memory, but it is not the mechanism to rely on for timely release of such resources.

Most IO classes implement Closeable, which is a specialization of AutoCloseable. That is why their natural lifecycle is expressed through the familiar try-with-resources construct.

Path path = Path.of("data.txt");

try (InputStream in = Files.newInputStream(path)) {
    byte[] data = in.readNBytes(32);
    System.out.println(data.length);
}

When control leaves the block — normally or because of an exception — Java calls close() automatically. This makes closing part of the program structure rather than a separate action that is easy to forget.

When there are several resources

Resources are declared from left to right and closed in reverse order. That is convenient for wrapper chains: the outer object is closed first, followed by the object on which it was built.

try (FileInputStream file = new FileInputStream("data.bin");
     BufferedInputStream buffered = new BufferedInputStream(file)) {
    System.out.println(buffered.read());
}

Here, buffered is closed first, then file. In practice, if the outer stream clearly owns the inner one, it is often enough to keep only the outer object as the resource, because its close() closes the chain further down.

The primary exception and suppressed exceptions

If an error occurs inside the block and another error occurs during close(), Java does not lose the original cause. The exception from the body remains the primary one, while the closing exception is attached as suppressed and is available through getSuppressed().

Close a resource where ownership of it is clear. A method that opened a stream for its own work should usually close it itself. But if a stream was supplied from outside and its lifecycle is controlled by the caller, unexpectedly closing it inside the method may be a design error.

What counts as a resource

try-with-resources is not only for files. It can manage any object that implements AutoCloseable: streams, readers/writers, channels, and many objects from other APIs. The main question is whether the object owns an external resource or state that must be released predictably.