53

I was wondering, whether is there any need for me to close the InputStream, after I close the reader?

try {
    inputStream = new java.io.FileInputStream(file);
    reader = new InputStreamReader(inputStream, Charset.forName("UTF-8"));
} catch (Exception exp) {
    log.error(null, exp);
} finally {
    if (false == close(reader)) {
        return null;
    }
    // Do I need to close inputStream as well?
    if (false == close(inputStream)) {
        return null;
    }
}
Matt Ke
  • 3,599
  • 12
  • 30
  • 49
Cheok Yan Cheng
  • 47,586
  • 132
  • 466
  • 875
  • 25
    Please use `if (!close(reader)` and not `if (false == close(reader))` – Jacob Tomaw Sep 02 '10 at 16:04
  • 5
    @Jacob Tomaw - WHY?! I have a very poor eye sight. "false" occupy more screen space than "!". This will at least make me more readable. – Cheok Yan Cheng Sep 02 '10 at 16:12
  • 10
    @Yan Cheng CHEOK it is poor style, and much harder to read for the next person to read your code. If you have trouble seeing the !, you need to either increase the font size of your computer or get stronger glasses, not create your own coding convention. – bwawok Sep 02 '10 at 16:14
  • 2
    @bwawok Or rearrange `if (!check) { thing(); return; } otherthing();` to `if (check) { otherthing() } else { thing(); }`. – Tom Hawtin - tackline Sep 02 '10 at 16:29
  • 9
    Oh and `return` in `finally`? Arghhhhhhhhhhhhhhhh!!! – Tom Hawtin - tackline Sep 02 '10 at 16:30
  • Funny how many bugs are in a 10 line demo to talk about closing streams.. methinks closing streams is the least of the problems :) – bwawok Sep 02 '10 at 17:12
  • @ Tom Hawtin - tackline May I know what's wrong of having return in finnaly? – Cheok Yan Cheng Sep 02 '10 at 18:02
  • 2
    @Yan Cheng It swallows exceptions, `return`s, `break`s and `continue`s. And it causes compiler lint warnings. (The C# dialect of Java-like languages gives errors, IIRC.) – Tom Hawtin - tackline Sep 03 '10 at 00:52
  • @ Tom Hawtin - tackline But I don't get any warning from my 1.6 Javac compiler. Is there any option I need to turn on? – Cheok Yan Cheng Sep 03 '10 at 02:37
  • FYI: you may need [`FileReader`](https://docs.oracle.com/javase/8/docs/api/java/io/FileReader.html) instead of an `InputStreamReader` reading a `FileInputStream`. – Franklin Yu May 08 '16 at 05:38
  • Why not return from finally? This may be useful to understand: https://stackoverflow.com/questions/48088/returning-from-a-finally-block-in-java – StvnBrkdll Oct 09 '19 at 14:47

5 Answers5

49

No, you don't have to.

Since the decorator approach used for streams in Java can build up new streams or reader by attaching them on others this will be automatically be handled by InputStreamReader implementation.

If you look at its source InputStreamReader.java you see that:

private final StreamDecoder sd;

public InputStreamReader(InputStream in) {
  ...
  sd = StreamDecoder.forInputStreamReader(in, this, (String)null);
  ...
}

public void close() throws IOException {
  sd.close();
}

So the close operation actually closes the InputStream underlying the stream reader.

EDIT: I wanna be sure that StreamDecoder close works also on input stream, stay tuned.

Checked it, in StreamDecoder.java

void implClose() throws IOException {
  if (ch != null)
    ch.close();
  else
    in.close();
}

which is called when sd's close is called.

Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
Jack
  • 131,802
  • 30
  • 241
  • 343
  • And the code for each of the concrete StreamDecoders also close the underlying inputstream where sd.close() is invoked ;-) – helios Sep 02 '10 at 16:08
  • 1
    Does it make any harm if I close the inputStream? – Cheok Yan Cheng Sep 02 '10 at 16:11
  • 2
    Did you find it explicitly written in the documentation? I'm not sure it is a constraint for all Java implementations. @Yan Cheng CHEOK: If you close the input stream after closing the reader, it does no harm. – Vivien Barousse Sep 02 '10 at 16:13
  • But it doesn't close it in a `finally`, right? so might not close it in an exception? It's dangerous to go on the source code, you should go only on the docs. – Sanjay Manohar Sep 02 '10 at 20:11
  • 2
    @Viven Barousse: "Closes the stream and releases any system resources associated with it." -- `java.io.Reader` JavaDoc for `close()` – Powerlord Sep 02 '10 at 20:35
  • True (modulo [bugs](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6266377)) but consider the answer below http://stackoverflow.com/a/3629116/281545. – Mr_and_Mrs_D May 03 '13 at 16:15
11

Technically, closing the Reader will close the InputStream. However, if there was a failure between opening the InputStream and creating the Reader, you should still close the InputStream. If you close the InputStream [the resource] there shouldn't be a good reason to close the Reader [the decorator]. There are also popular bugs where closing a decorator can throw an exception before closing the decorated. So:

Resource resource = acquire();
try {
    Decorator decorated = decorate(resource);
    use(decorated);
} finally {
    resource.release();
}

There are some complications to watch out for. Some decorators may actually contain native resources due to their implementation. Output decorators will generally need to be flushed, but only in the happy case (so in the try not the finally block).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • 2
    This fails if `Decorator` is for example a `BufferedWriter`. It's nowhere explicitly documented that a programmer should explicitly call `flush()` after use. – BalusC Sep 02 '10 at 16:36
  • @BalusC I'm confused. The first line of the `BufferedWriter` API docs says that it buffers characters. – Tom Hawtin - tackline Sep 02 '10 at 22:52
  • `BufferedWriter` (decorated) will `flush()` on `close()`. The `FileWriter` (resource) for example doesn't do that. So you risk unflushed chars when you close only the `FileWriter` – BalusC Sep 02 '10 at 23:17
  • @BalusC As I say in the answer, output decorators will generally need to be flushed. They're kind of an unusual resource. `FileWriter` is a disaster. – Tom Hawtin - tackline Sep 03 '10 at 00:50
  • Could you please elaborate on "decorators may actually contain native resources due to their implementation" in your answer (maybe also format the "complications" part as a list). Very useful +1 – Mr_and_Mrs_D May 03 '13 at 16:23
  • @Mr_and_Mrs_D For OpenJDK some of the compression-related streams use native code with buffers allocated on the C heap, which require explicit deallocation. For those sorts of streams it's technically insufficient just to close the underlying stream (although finalisers should release the memory in their own time). The nasty thing is that the behaviour doesn't get documented. – Tom Hawtin - tackline May 03 '13 at 16:42
5

You don't have to close stream, if you close() the reader.

Closes the stream and releases any system resources associated with it. Once the stream has been closed, further read(), ready(), mark(), reset(), or skip() invocations will throw an IOException. Closing a previously closed stream has no effect.

palacsint
  • 28,416
  • 10
  • 82
  • 109
amorfis
  • 15,390
  • 15
  • 77
  • 125
3

No you don't the reader will close the underlying InputStream

Jon Freedman
  • 9,469
  • 4
  • 39
  • 58
0

Acordding to source sniffing the reader closes its underlying inputstream. According to javadoc it seams that InputStreamReader "closes the stream" when reader.close() is invoked.

I'm not sure if ANY Reader must close its sources when you do reader.close(). I think that this is important so your code can use a reader no matter what concrete type it is.

Anyway it makes sense that it's enforced.

helios
  • 13,574
  • 2
  • 45
  • 55