10

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.

  • Not a Java developer, but I would use these rules: - If a stream is passed as an argument, document that the caller must close the stream if needed; - If the stream is returned to you from a functions, assume you need to close it. – Bart van Ingen Schenau Nov 19 '15 at 8:02
5

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.

  • So basically close is the only safe alternative? I guess the question is how not to make code look overly ugly every time a Stream would be handy to use. – RuslanD Nov 18 '15 at 23:39
  • 1
    Yes, if there might be non-memory resources, the only safe thing to do is assume there are. No way around it, even though Java is very ill-suited for non-GC'd resources. – Deduplicator Nov 18 '15 at 23:43
  • So if it's just a stream between two collections (pure memory), closing it isn't necessary? – Amalgovinus Jan 17 '17 at 18:10
  • @Amalgovinus correct – Brad Cupit May 16 '18 at 14:31
4

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 { ... }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.