Closing Java Streams
Fast recall
Quick revision
Core answer
Interview-ready guide
Interview answer
Closing a Java stream ends its lifetime and releases the resource behind it. File and socket streams can hold operating-system file descriptors or network connections. If a program leaks enough of them, later opens can fail. Output streams and writers may also have buffered data that must be finished before the resource is released.
Try-with-resources is the normal solution for a stream owned by the method. Java closes every declared resource when the block ends, even if reading or writing throws an exception. Resources close in reverse declaration order, and if both the work and closing fail, the close failure is kept as a suppressed exception.
For example, a BufferedWriter returned by Files.newBufferedWriter(path) should be opened in try-with-resources. The program writes the text inside the block, and Java closes the writer afterward. Closing the outer wrapper normally flushes its pending characters and closes the file stream below it.
The important boundary is ownership. Close a stream that your code opens, but do not close a stream that another API only lends unless its contract says you own it. flush() makes buffered output visible while keeping the resource open; close() ends its use. Some in-memory streams have a no-op close, but that special case is not a reason to ignore closing for files, sockets, or format wrappers.
Closing Java Streams
Direct Answer
Streams must be closed to release owned operating-system resources and finish buffered output. Use try-with-resources so closing happens on success and failure; close the outer owned wrapper, and do not close a borrowed stream whose lifetime belongs to another component.
Deep Dive & Architecture
Buffered output delays some writes, so an error can surface only during flush or close. Treat that close failure as part of the operation's outcome when durability matters. Logging “saved” before the resource closes can report success too early.
Try-with-resources handles two simultaneous failures without discarding either. The exception from the body remains primary, and failures from close are attached through getSuppressed(). The older finally pattern often overwrote the original failure or forgot one branch.
Garbage collection is not a resource-lifetime mechanism. It does not promise prompt reclamation of external handles, and a process can exhaust descriptors long before heap pressure triggers collection.
Code Example
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
class ClosingStreams {
public static void main(String[] args) throws Exception {
Path file = Files.createTempFile("close-demo-", ".txt");
try {
try (var writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
writer.write("complete");
}
System.out.println(Files.readString(file, StandardCharsets.UTF_8));
} finally {
Files.deleteIfExists(file);
}
}
}
Check your understanding
Answer these without looking back at the article.
- What is the difference between flush and close?
- How does try-with-resources preserve two exceptions?
- Should a method close a stream supplied by its caller?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.