30

The java.io.InputStream.close() method is declared to throw an IOException. Under what circumstances would such an exception actually be thrown?

Edit: Yes I have read the javadoc. Can anybody be more specific than "when an I/O error occurs"? What I/O error can occur while closing an InputStream?

meriton
  • 68,356
  • 14
  • 108
  • 175
  • 6
    if an I/O error occurs. – Salah Eddine Taouririt May 04 '13 at 00:45
  • Maybe if it is already closed? – Martinsos May 04 '13 at 00:45
  • @meriton I think you will find your answer to "What I/O error can occur... " question in the IOException class not in InputStream class javadoc. As mentioned in my answer I too expected it to be in InputStream, could not find it and had my "Ahha" moment when looking at all the subclasses of IOException. – smallworld May 04 '13 at 01:02
  • 4
    @Martinsos: The JavaDoc of `java.io.Closable.close` writes: If the stream is already closed then invoking this method has no effect. – meriton May 04 '13 at 01:05

4 Answers4

21

In the case of input stream reading from a file system, an error can be raised while the file system itself updates the last access time metadata, or some other metadata, on a file during closure. Anyway, this happens almost never in practice.

In the case of an input stream reading from a network connection, an error on closure is a bit more conceivable. A normal closure of a network socket actually involves a closure request (TCP/IP FIN packet) being sent over the connection and waiting for the other end to acknowledge this closure request. (In fact, the other end of the connection then in turn sends a closure request, which the closing end acknowledges.) So in the case of a socket input stream, a closure operation actually involves sending traffic over the connection and the closure can thus fail with an error.

Note that in many implementations, close() generally doesn't throw an IOException if the stream is already closed; it simply fails silently to close the stream again.

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
5

I'm looking through the Java source code, and have found something interesting which is indicative of the IOException reason. InputStream is an abstract class. We therefore can't predict the kind of input which will be closed, so it's good to keep information flowing.

Whatever code uses that input stream needs to be able to throw an IOException, because there is a chance that closing the input stream may fail. If it fails, whatever's using the implementation needs to know about it, because there's a good chance it needs to be handled.

It's important to understand the layout of the Exception structure in Java. Every exception, of course, extends Exception. However, there are also broader categories of exceptions: java.lang.IOException is one of these, and covers all possible input/output exceptions. When we say there has been an I/O error, we're referencing anything which falls under IOException. As a result, many exceptions extends this one, e.g. FileNotFoundException, EOFException, etc. as it's important to have a broad, overarching exception to manage these.

As a result, any IO class will need to be able to throw any of the various IOExceptions on close. close() therefore must throw IOException - this gives its implementation the ability to throw any of the extensions of IOException as well. This is why close() throws IOException - exceptions are inherited, and you need to be able to any of the IOExceptions when closing a stream.


Here are a couple scenarios worth noting:

  • You can't close an IOStream twice, though this generally doesn't throw an exception if you do
  • The content becomes inaccessible (e.g. a disk was unmounted) (The close() is actually critical for the operating system, as it needs to have an indicator of when the file is no longer busy)
  • The generic source has closed
  • Any generic failure not covered by all other subclasses of IOException (e.g. FileNotFoundException)

You can check what caused an IOException by running Exception.getMessage().

  • Closing a closed stream "has no effect" according to the JavaDoc of `java.io.Closable.close`. As for the other causes, I see how they could occur when opening or reading from a stream, but when closing? – meriton May 04 '13 at 01:10
  • @mertion Well... yes. For instance, if you're reading from a disk, the closure step is _critical_ in telling the operating system nothing's using the file anymore. If the program can't do that, it makes sense to alert the program. –  May 04 '13 at 01:11
  • @meriton I figured out the exact reason why it exists. Please see my edits. –  May 04 '13 at 01:17
  • Why could telling the operating system that it may free the file descriptor fail? And what good would it to to tell the program about that? I mean, if the operating system won't close the file when asked, what can the progam do? – meriton May 04 '13 at 01:22
  • @meriton The program can handle the error, or not. It's really up to the implementation of `InputStream` - remember, **InputStream is abstract**. We can't predict the kind of input which will be closed, so it's good to keep information flowing. I would be livid if I needed to handle that error, but couldn't, because there was an un-overridable implementation. That's why we throw exceptions in the first place: so the rest of the code can handle them, or not. Additionally, freeing the file descriptor may fail if the disk is no longer accessible at the time of closure. –  May 04 '13 at 01:24
  • @meriton Edited again (reorganizing, and clarifying some key points) –  May 04 '13 at 01:29
  • 1
    I may be wrong, but it seems like throwing some kind of unchecked Exception would have been a better design choice for the `close()` operation. – crush Sep 05 '13 at 18:28
4

The underlying close system call will have to be made eventually, e.g. on linux http://linux.die.net/man/2/close. That call is documented to fail with EIO: "An I/O error occurred." So the reason is, that the underlying file system close call can fail.

Kevin
  • 24,871
  • 19
  • 102
  • 158
1

I have wondered about this myself and have done a little research on this topic few years ago. This is what I know....

If you look at the javadoc in the link you provided, it clearly states that "The close method of InputStream does nothing", so there is no way it would throw an exception, correct? But then looking at all of the subclasses of IOException you will see that there are many situations where subclasses of inputstream may not be able to close the stream. So my best guess is that this exception is designed for subclasses to make use of it.

http://docs.oracle.com/javase/6/docs/api/java/io/IOException.html

In some cases, it is nothing more than a nuisance, and in others it clearly indicates that something went wrong. It all depends on what type of inputstream implementation you are making use of.

smallworld
  • 910
  • 7
  • 15
  • And by the way, StackOverflow showed me this in the right column which I thought was an interesting discussion on a very similar topic. See if this helps explain... http://stackoverflow.com/questions/2766450/when-does-java-util-zip-zipfile-close-throw-ioexception?rq=1 – smallworld May 04 '13 at 01:05