views:

250

answers:

4

Do you agree that the designers of Java class java.io.IOException should have made it an unchecked run-time exception derived from java.lang.RuntimeException instead of a checked exception derived only from java.lang.Exception?

I think that class IOException should have been an unchecked exception because there is little that an application can do to resolve problems like file system errors. However, in When You Can't Throw An Exception, Elliotte Rusty Harold claims that most I/O errors are transient and so you can retry an I/O operation several times before giving up:

For instance, an IOComparator might not take an I/O error lying down, but — because many I/O problems are transient — you can retry a few times, as shown in Listing 7:

Is this generally the case? Can a Java application correct I/O errors or wait for the system to recover? If so, then it is reasonable for IOException to be checked, but if it is not the case, then IOException should be unchecked so that business logic can delegate handling of this exception to a separate system error handler.

+1  A: 

No because you can recover from some IOExceptions. Most notable ones are low level indexed reads and writes. If it fails, sometimes you can just retry without harm.

Pyrolistical
+4  A: 

I completely disagree. To me the model is correct. A RuntimeException is one which most typically denotes a serious error in the logic of the programming (such as ArrayIndexOutOfBounds, NullPointer, or IllegalArgument) or something that the runtime has otherwise determined really shouldn't be happening (such as SecurityException).

Conversely IOException and its derivatives are exceptions that could reasonably occur during normal execution of a program, and common logic would dictate that either those problems should be dealt with, or at least the programmer should be aware that they can occur. For example with Files if you're application logger can't write its data would you rather be forced to catch a potential IOException and recover, or have something that may not be critical to your app bring down the whole JVM because no one thought to catch the unchecked Exception (as you may have guessed, I'll choose the former).

I think that there are many situations in which an IOException is either recoverable, or at the least the programmer should be explicitly aware of the potential so that if it is not recoverable the system might be able to crash more "gently".

As far your thought of if the system can not recover there are always alternatives with a checked exception. You can always have your methods declare it in their throws, throw a runtime excpetion of their own or crash the JVM violently:

public void doit() throws IOException {
  try{
  }catch(IOException e){
    //try to recover
    ...

    //can't recover
    throw e;
  }
}

public void doit() {
  try{
  }catch(IOException e){
    //try to recover
    ...

    //can't recover
    throw new RuntimeException(e);
  }
}



public void doit() {
  try{
  }catch(IOException e){
    //try to recover
    ...

    //OH NO!!!!
    System.exit(Constant.UNRECOVERABLE_IO_ERROR);
  }
}
M. Jessup
In http://www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html, Barry Ruzek disagrees: "An I/O failure is a serious but extremely rare event. On top of that, there is usually nothing your code can do to recover from one." According to Ruzek, many Java libraries throw this exception, which suggests that they follow your first approach to recovering from an `IOException`. However, if some method fails to recover from an `IOException`, what's the point of throwing it higher when it's unlikely that the client could recover anyway?
Derek Mahar
I disagree with "extremely rare" events. Consider a network socket. It is completely reasonable for a client Socket to become disconnected and if you are trying to write or read data this will cause an IOException. For recovery I think you need to be careful about your definition of "recovery". In the socket example you may lose the client connection, but recovery may be a process such as freeing resources that were used by the severed connection. Similarly for rethrowing you may want to log the event close to the originator, but allow something higher up the stack to deal with it.
M. Jessup
So in what case would you advise re-throwing a `RuntimeException` after recovery fails? Isn't this little different than (and just as bad as) an unchecked `IOException`?
Derek Mahar
EOFException is not 'extremely rare'. It is expected once per connection. And exceptions aren't part of a recovery model anyway - see the extensive discussion in Stroustrup's writings.I completely agree with M. Jessup on this. Fortunately the question is moot as Java is a done deal.
EJP
@Derek I am not advocating the rethrow of a RuntimeException. I merely provided that as an example of how one could "simulate" an IOException as being unchecked if for some reason that is desired behavior (which I can't think of a reasonable example where it would be). Similarly for using System.exit as an alternative for failed recovery (perhaps I should have also included the sarcastic "//OH NO!!!!!" for the RuntimeException example). In any case I believe the proper strategy is to catch, attempt to recover if possible, and then rethrow, or return an appropriate value from the method.
M. Jessup
@EJP: Yes, the Java libraries are a done deal, but the design of Java's exception model and libraries can instruct the proper design of new Java libraries and the exception model of new languages that run on the JVM. For example, the Spring Framework believes that, "Checked exceptions are overused in Java. A platform shouldn't force you to catch exceptions you're unlikely to be able to recover from." Scala, a relatively new language that runs on the JVM, does not support checked exceptions. Is this for better or worse?
Derek Mahar
What am I being asked here? I've stated my position and by implication I disagree with the counter-position.
EJP
@EJP: My question about Scala was mostly rhetorical. My point was that even though Java is a "done deal", the question is not entirely moot. It's still useful to discuss retrospectively about the whether the original Java design decisions were appropriate so that we may avoid repeating any mistakes in future Java libraries or JVM languages, like Scala.
Derek Mahar
@EJP: In http://beust.com/weblog/2010/04/25/improving-exceptions/, Cédric Beust, creator of TestNG, does not consider the question moot, either: "In the future, I’d like to see discussions on this topic focused more on where and when to use checked exceptions and runtime exceptions instead of reading articles telling you that you should always do "this" and never do "that"."
Derek Mahar
Again I still don't know what I'm being asked, or told, here. IOException is a checked exception in Java. Period. I like it that way and indeed I like checked exceptions. You are free to disagree but then it ceases to be a question about Java. EOFException has to be dealt with once per connection unless you are using lower-level I/O methods, so making it a RuntimeException doesn't make sense.
EJP
+2  A: 

I think it is clever to leave it a checked exception. I regard runtime exceptions as bugs, and this is clearly not the case. Recovery by retry is sometimes possible, and also some IOException messages can be informative to the end user (e.g. no permissions to write, not enough disk space, etc).

Eyal Schneider
I regard checked exceptions as a **bug** in the language design. You say it yourself: an IOExcpetion message can be informative to the user - but what good is that to the low-level IO method that has no business with the UI and yet is forced to catch the exception or pollute its signature with it?
Michael Borgwardt
Michael, do you mean the low-level I/O method is forced to catch the exception and pollute its signature, or the UI level code?
Derek Mahar
@Michael: IMO the signature is not polluted at all. Just as you specify the returned value type, you should also specify other kind of legitimate outcomes of the action. It has both a practical and a declarative importance.
Eyal Schneider
@Derek: I meant the low-level IO code. @Eyal: that's the theory. In practice, it results in horribly leaky abstractions and massively polluted APIs - because we're not talking about just that one method, but everything between it and the point where the exception is finally caught, for every method from which it is called. And the same for every other method that throws checked exceptions.
Michael Borgwardt
+1  A: 

Probably the vast majority of IO exceptions are recoverable - permissions errors, lack of space on the drive, connection closed, etc, etc. I believe unchecked exceptions are supposed to be used for "there's no reasonable way to recover from this" sorts of situations.

Mark Bessey