Frage

Quoth the Javadoc:

Streams have a BaseStream.close() method and implement AutoCloseable, but nearly all stream instances do not actually need to be closed after use. Generally, only streams whose source is an IO channel (such as those returned by Files.lines(Path, Charset)) will require closing. Most streams are backed by collections, arrays, or generating functions, which require no special resource management. (If a stream does require closing, it can be declared as a resource in a try-with-resources statement.)

"Nearly all" and "generally" are vague - if you're writing a library and you're abstracting the source of your Stream from the users of that Stream, then you always anyway have to ask yourself the question - "should I close this?" IO-backed Streams need to be closed because terminal operations don't call close, so effectively I always have to either remember/document where my Stream is coming from, or I always have to close it.

The nuclear option I guess would be to not return Streams from methods or accept Stream parameters, which is a sentiment that has been echoed by some people on the JDK team. I find that to be overly limiting considering the practical usefulness of Streams.

What are your best practices around closing Streams? I looked online for an answer to this from some of the JDK folks who are usually active on similar community questions, but didn't find anything relevant.

War es hilfreich?

Lösung

As you said, in Java you need to know exactly who is responsible for freeing which resource, so you can put in the appropriate try-catch-constructs, try-with-resources or somehow delegate that task.

The only thing which you can depend on the GC to clean up for you is 100% pure memory.
If there might be some other resources mixed in, the only thing you can reasonably do is simply playing it safe.

Andere Tipps

As far as "best practices" goes, I think it's a good idea to use a naming convention for methods that return "resource streams".

If a stream has to be close()ed, call the factory method open() or openStream(). Call methods that construct ephemeral streams stream(), following the convention established by the SDK. Always put javadoc on the method to alert the client that they must close() it.

public interface StreamingServer<RECORD> {
    /** 
     * Return a memory-efficient record stream from {@code source}.
     * Clients <em>must</em> call {@link Stream#close} to dispose the
     * stream.
     */
    Stream<RECORD> openStream(URI source) throws IOException;
}

I wish the SDK authors had not chosen to put AutoCloseable on the base stream class. A distinct ResourceStream subtype, which trivially implements AutoCloseable, would have made the different contracts obvious. Then you couldn't close a Stream that doesn't need it, and you could detect potentially mismanaged ResourceStream in static analysis tools.

Depending on the needs of your codebase (and your ability to enforce conventions in code review), you could establish a close-required stream subclass yourself. Or if you want to build your own static analysis tools, a method annotation that marks managed resources directly.

@RequiresClose
Stream<RECORD> openStream(URI source) throws IOException { ... }
Lizenziert unter: CC-BY-SA mit Zuschreibung
scroll top