Unit 14 · lesson

Try-With-Resources Makes Ownership Explicit

Some Java APIs open resources that must be closed: files, streams, readers, sockets, database connections, and more.

A resource leak is not a syntax error. The code can compile and run while gradually exhausting system resources or holding locks longer than intended.

Java's try-with-resources ties cleanup to scope.

Full-JDK example

import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

class ReaderDemo {
    public static void main(String[] args) throws IOException {
        Path path = Path.of("data", "matches.csv");

        try (BufferedReader reader = Files.newBufferedReader(path)) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

The BufferedReader is declared in the try (...) resource header. Java closes it when control leaves the block, including when an exception interrupts normal flow.

Ownership is the design question

Ask:

Who opens this resource?
Who owns the responsibility to close it?
How long should it live?
What happens if processing fails halfway through?

A clear ownership boundary reduces cleanup bugs.

Read-all versus streaming

Files.readAllLines is simple and useful for small classroom files because it returns all lines as a collection.

A buffered/streaming approach can process data incrementally and avoid loading the whole file at once.

Do not turn this into "streaming is always better." The choice depends on file size, access pattern, error handling, simplicity, and memory constraints.

Parsing failures inside a resource scope

Suppose line 30 is malformed. Try-with-resources will still close the reader when parsing throws.

That does not decide whether the application should:

  • stop the whole import;
  • skip the bad line;
  • collect errors and continue;
  • reject the file as a unit.

Resource cleanup and domain failure policy are separate concerns.

Browser-core design exercise

Even without a filesystem, draw:

open resource
  |
read next record
  |
parse / validate
  |
process
  |
close resource

Mark which arrows are environment I/O responsibilities and which are pure parsing/domain responsibilities.

Then test the parser with a supplied malformed line and explain what would happen to resource cleanup in the full-JDK version.

Evidence

Full-JDK lane: run one try-with-resources example using a fictional local file and document successful read plus one controlled failure.

Browser lane: submit the ownership diagram, parsing tests, and an explanation of why this evidence proves parser behavior but does not prove real filesystem access.

Being precise about what an experiment did not test is part of engineering evidence.