How to properly handle an IOException from close()

前端 未结 9 1556
滥情空心
滥情空心 2021-02-05 08:14

The Java I/O classes java.io.Reader, java.io.Writer, java.io.InputStream, java.io.OutpuStream and their various subclasses al

相关标签:
9条回答
  • 2021-02-05 08:34

    "Ignoring or just logging is usually a bad idea." That's not answering the question. What should one do about an IOException from close()? Just rethrowing it only pushes the problem further up, where it's even more difficult to handle.

    Theory

    To answer you question directly: When this IO action failed, then depending on the circumstances, you may want to

    • rollback changes (don't leave a partially written file on the disk, delete it)
    • retry (maybe after a rollback)
    • ignore (and continue)
    • interrupt the current task (cancel)

    You can often see the last 3 in dialog boxes shown to the user. Indeed, delegating choice to the user is a possibility.

    I believe the main point is to not leave the system in an inconsistent state. Just swallowing a close exception might leave you with a crippled file, causing nasty errors later on.

    Practice

    It is a bit cumbersome to work with checked exceptions. Options arise:

    • Convert them to RuntimeException, throw them and leave them to be handled at a sufficiently high level

    • Keep using checked exceptions and suffer the syntactic pain

    • Use more composable error handling constructs, like the IO monad (not really available in Java, at least not without embarassingly many braces (see http://apocalisp.wordpress.com/2008/05/16/thrower-functor/) and not with full power)

    More on IO monad

    When you return a result in the IO monad context, you are not actually executing an IO action, but rather return the description of that action. Why? These actions have an API with which they compose nicely (versus the throws/try/catch massacre).

    You can decide if you wish to do check exception style handling (with Option or Validation˙ in the return type), or dynamic style handling, with bracketing only on the finalunsafePerformIO` call (which actually executes the composed IO action).

    To get some idea, see my Scala gist http://gist.github.com/2709535, which hosts the executeAndClose method. It returns both the result of the resource processing (if available) and an unclosed resource (if closing failed). It is then the users decision how to deal with such an unclosable resource.

    It could be beefed up with Validation/ValidationNEL instead of Option if one needs the one/more actual exceptions too.

    0 讨论(0)
  • 2021-02-05 08:35

    It depends on what you are closing. For example, closing a StringWriter does nothing. The javadocs are clear on that. In this case, you can ignore the IOException because you know that it will never be generated. Technically, you don't even need to call close.

    /**
     * Closing a <tt>StringWriter</tt> has no effect. The methods in this
     * class can be called after the stream has been closed without generating
     * an <tt>IOException</tt>.
     */
    public void close() throws IOException {
    }
    

    For other streams, log and handle the exception as appropriate.

    0 讨论(0)
  • 2021-02-05 08:35

    Generally resource handling should look like this:

    final Resource resource = context.acquire();
    try {
        use(resource);
    } finally {
        resource.release();
    }
    

    In (the unlikely) case of release throwing an exception, any exception thrown by use will be dropped. I don't have a problem with the exception thrown closest to the catcher winning. I believe ARM blocks in JDK7(?) will do something crazy in this case, like rethrowing the use exception with the release exception attached.

    If you use the Execute Around idiom, you can put these decisions and potentially messy code in one (or few) places.

    0 讨论(0)
  • 2021-02-05 08:37

    Try to use flush before you close the writer. The main reason for exception in close is that some other resources might have been using the data or the writer/reader may not be open at all. try to find wheather the resoures is open before closing it.

    0 讨论(0)
  • 2021-02-05 08:38

    First of all don't forget to put the close() inside the "finally" section of your try catch block. Second you can surround the close method with another try catch exception and log the exception.

    0 讨论(0)
  • 2021-02-05 08:40

    Well, in most cases, close() doesn't actually throw an IOException. Here's the code for InputStream.java:

      public void close() throws IOException
      {
        // Do nothing
      }
    

    Errors from closing a network resource should really be of some type of RuntimeException, since you can disconnect a networked resource after the program connects to it.

    You can see some example of various implementations of Reader/Writer and Streams using Google Code Search. Neither BufferedReader nor PipedReader actually throw an IOException, so I think you're mostly in the safe by not worrying about it. If you're really worried, you can check the implementation of the libraries you're using to see if you ever need to worry about the exception.

    Like others mentioned, you can't do much about the IOException other than log it.

    After all, try/catch blocks in the finally clause are pretty ugly.

    Edit:

    Further inspection reveals subclasses of IOException like InterruptedIOException, SyncFailedException, and ObjectStreamException, along with classes that inherit from it. So just catching an IOException would be too general -- you wouldn't know what to do with the information other than logging it because it could be from a whole range of errors.

    Edit 2:

    Urk, BufferedReader was a bad example, since it takes a Reader as input. I've changed it to InputStream.java

    However, there's a hierarchy with InputStream <= FilterInputStream <= BufferedInputStream <= InputStreamReader (via inheritance and private instances) that all trickle up to the close() method in InputStream.

    0 讨论(0)
提交回复
热议问题