简体   繁体   中英

Should class IOException in Java have been an unchecked RuntimeException?

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.

我知道这个问题被问到已经 4 年了,但是在 Java 8 中添加了UncheckedIOException

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 your 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 exception 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);
  }
}

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 (eg no permissions to write, not enough disk space, etc).

可能绝大多数 IO 异常都是可恢复的——权限错误、驱动器空间不足、连接关闭等。我相信未经检查的异常应该用于“没有合理的方法可以从这种情况中恢复”的情况.

In a well-designed exception framework, a distinction should be made between exceptions which are to some extent "expected" and those which are not. Java attempts to use checked versus unchecked exceptions for this. By that standard, IOException should be a checked exception.

A fundamental problem, though, is that oftentimes code will be written with a (perhaps reasonable) expectation that a certain exception will not occur, and nothing can usefully be done to handle it if it does. If a method is declared as throwing a particular checked exception, Java allows its caller to ignore the exception if it declares itself as throwing that exception, but there's no means by which a method or code block can specify that certain exceptions from called methods are not expected to occur . A common anti-pattern is:

try
{
  methodThatsDeclaredAsThrowingFooExceptionButWont()
}
catch FooException Ex
{
  // Never going to happen
}

The apparent assumption is that since the method won't throw FooException and the only reason the catch is there is to make the compiler happy, there's no reason for the catch to do anything. Insidious, because if a FooException does get thrown, for whatever reason, it will go undetected.

An alternative is for a method which calls methodThatsDeclaredAsThrowingFooExceptionButWont to declare itself as throws FooException or throws Exception , but that isn't really appropriate either. If a method which is not expected to throw a FooException does, the system state is apt to be different from what it would be expected when a FooException is thrown.

For example, suppose one attempts to load a document, but the document-load routine needs to read some non-document-specific translation tables which are supposed to be stored at a fixed location; if that attempt fails, having the IOException percolate up to the caller would imply that there was a problem loading the document being loaded. If the load-document routine isn't prepared to sensibly handle the possibility that the load-translation-tables routine might fail, such failure shouldn't percolate up the same way as would an IOException that occurred while actually loading the document.

The proper remedy would not be for IOException to be an unchecked exception, but rather for there to be a declarative means by which code could indicate that one or more kinds of checked exceptions should not be allowed to percolate out of a certain block from methods called thereby, but should instead be wrapped in some other exception type (eg RuntimeException).

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM