views:

61

answers:

3

I'm creating a Java method that accepts a single InputStream as an argument. For the convenience of working with a character-based stream, I wrap the provided InputStream at the start of the method implementation as follows:

public void doStuff(InputStream inStream) {
   BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
   ...
}

Since the InputStream (inStream) is passed to my method, I don't want to close it ... as I think that should be the responsibility of the client calling my method (is this assumption correct?). However, I do think that I should close the BufferedReader that I created; but in doing so, I believe it will automatically close all the other composed streams including the inStream.

Does anyone see a way for me to close the BufferedReader and InputStreamReader that I created while not closing the InputStream passed to my method? Maybe there is a way to make a copy of the provided InputStream before I wrap it? Thanks

A: 

What I'd try would be overriding the close method:

BufferedReader reader = new BufferedReader(new InputStreamReader(inStream)){
    public void close() throws IOException {
        synchronized (lock) {
            if (in == null)
                return;
        }
    }
};
// rest of your code

Kind of crazy, but it should work. Though, I'm not sure this is the best approach.

I think this is an interesting question, so I hope someone expert gives his/her opinion.

Cristian
+2  A: 

Personally I would just avoid the problem by changing the signature of your method to require that a BufferedReader (or Reader) be passed in.

fd
This propagates the creation of the BufferedReader to the caller. But what if the calling method gets its stream from somewhere else, too?
Christian Semrau
You hava a good point: One might wish to provide a `Reader` based version, too. Because, if someone gets an `InputStream` with a non-default encoding, she cannot use the stream based method, because the InputStreamReader uses the wrong encoding.
Christian Semrau
The `java.util.Properties` class provides both `load(InputStream inStream)` and `load(Reader reader)` methods. I think having both options available to possible clients of your class is a convenience that can simplify the client code. That is, the client doesn't have to wrap an `InputStream` to get a `Reader` before passing it as an argument to the method.
+2  A: 

You do not need to close a BufferedReader or InputStreamReader or probably most reader implementations, when you do not wish to close the underlying reader.

These readers do not hold any resources that a call to close() would make free and which the garbage collector would not make free anyway (e.g. native resources or values in static variables) when you drop the reference to the reader at the end of your method.

The underlying input streams that communicate with native resources, e.g. FileInputStream or streams obtained from URLs, must be closed to free those native resources.

For Writer, there's a difference in that close() usually calls flush(). But then, you can call flush() directly.

Christian Semrau
Yes, although some compression streams (though not `Readers` as far as I am aware) use native resources and need to be closed.
Tom Hawtin - tackline
Indeed. So when you wanted to concatenate several output streams, each compressed by itself, into one output stream, one options is to override the close method as @Cristian C. suggests. (Something similar probably happens when using compressed archives containing several files.)
Christian Semrau
The javadoc for the `BufferedReader` `close()` method says "Closes the stream and releases any system resources associated with it." I'm assuming this is still correct and doesn't imply "native system resources". In any event, I may be naively following the "close all streams when you are done with them" idiom but in general would like to avoid looking at the source code of a particular stream class to see if it is OK to leave it open.