在Java中检查vs未经检查的exception

我在理解Java中已checkeduncheckedexception之间的差异时遇到了一些问题。

  1. 首先, checkedexception应该在编译期间查找exception。 在不同来源中提供的示例引用数据库连接,文件处理作为其中一些,而uncheckedexception应该在程序员的部分寻找错误,例如超出数组范围的索引等。

不应该反过来吗? 我的意思是,数据库连接是在运行时完成的,对吧? 文件处理也是如此。 您在编译期间没有打开文件句柄,那么为什么在编译期间会查找可能的错误? 另一方面,在程序中已经完成了索引超出其范围的数组,可以在编译期间检查(如果用户在运行时提供exception索引,那么它可以是运行时)问题)。 我在这里想念的是什么?

2其次, RunTimeException本身如何被unchecked ,子类Exception ,哪个被checked ? 这意味着什么?

我在Herbert Schildt的书中找到了一个例子,解释了checkedexception的用法:

 class ThrowsDemo { public static char prompt(String str) throws java.io.IOException { System.out.print(str + ": "); return (char) System.in.read(); } public static void main(String args[]) { char ch; try { ch = prompt("Enter a letter"); } catch(java.io.IOException exc) { System.out.println("I/O exception occurred."); ch = 'X'; } System.out.println("You pressed " + ch); } } 

这里需要throws条款吗? 为什么我不能正常使用像这样的try-catch语句(对不起我不知道如何模拟IO Exception ,因此无法自己检查它):

 class ThrowsDemo { public static char prompt(String str) { System.out.print(str + ": "); return (char) System.in.read(); } public static void main(String args[]) { char ch; try { ch = prompt("Enter a letter"); } catch(java.io.IOException exc) { System.out.println("I/O exception occurred."); ch = 'X'; } System.out.println("You pressed " + ch); } } 

CheckedException需要由调用者处理,Uncheckedexception不需要。

因此,在设计应用程序时,您应该记住您正在管理的exception情况。

例如,如果您设计一个validation方法来检查某些用户输入的有效性,那么您就知道调用者必须检查validationexception并以一种漂亮的方式向用户显示错误。 这应该是一个经过检查的例外。

或者,对于那些可以恢复的特殊情况:假设您有一个负载均衡器,并且您希望通知呼叫者其中一个“n”服务器已关闭,因此呼叫者必须恢复事件,将该消息重新路由到另一个服务器; 这应该是一个已检查的exception,因为调用者(客户端)尝试恢复错误是至关重要的,并且不要让错误破坏程序流。

相反,有许多条件不应该发生,和/或应该打破程序。 例如,编程错误(如除零,空指针exception),错误使用API​​(IllegalStateException,OperationNotSupportedException),硬件崩溃,或只是一些无法恢复的小情况(与服务器的连接丢失),或世界末日:-); 在这些情况下,正常处理是让exception到达代码的最外部块,向用户显示发生了不可预测的错误,并且应用程序无法继续执行任何操作。 这是一个致命的情况,所以你唯一能做的就是将它打印到日志或在用户界面中显示给用户。 在这些情况下,捕获exception是错误的,因为在捕获exception后,您需要手动停止程序以避免进一步损坏; 所以最好让某种例外“击中粉丝”:)

由于这些原因,在JRE中还存在一些未经检查的exception:OutOfMemoryError(不可恢复),NullPointerException(这是需要修复的错误),ArrayIndexOutOfBoundsException(另一个错误示例),依此类推。

我个人认为也应该取消选中SQLException,因为它表示程序中的错误或数据库的连接问题。 但是有很多例子你会得到一个例外,你真的没有任何关于如何管理的线索(RemoteException)。

处理exception的最佳方法是:如果您可以恢复或管理exception,请处理它。 否则让exception传出; 别人需要处理。 如果您是最后一个“其他人”并且您不知道如何处理exception,只需显示它(在UI中记录或显示)。

  1. 您不需要在throws子句中声明未经检查的exception; 但是你必须声明已检查的例外;
  2. RuntimeExceptionError以及它们的所有子类( IllegalArgumentExceptionStackOverflowError等)都是未知的exception; 与其他Throwable子类不同, RuntimeException未经检查的事实是设计的;
  3. 没有“编译时间exception”之类的东西。

更一般地,认为在JVM错误或程序员错误的情况下抛出未经检查的exception。 一个着名的例外是NullPointerException ,通常缩写为NPE,它是RuntimeException的子类,因此未经检查。

未经检查的exception与已检查exception之间的另一个非常重要的区别是,在try-catch块中,如果要捕获未经检查的exception,则必须明确地捕获它们

最后注意事项:如果您有E1E2exception类,并且E2扩展了E1 ,那么捕获和/或抛出E1也会捕获/抛出E2 。 这代表已检查和未检查的exception。 这对catch块有意义:如果你区分捕获E2E1 ,你必须首先捕获E2

例如:

 // IllegalArgumentException is unchecked, no need to declare it public void illegal() { throw new IllegalArgumentException("meh"); } // IOException is a checked exception, it must be declared public void ioerror() throws IOException { throw new IOException("meh"); } // Sample code using illegal(): if you want to catch IllegalArgumentException, // you must do so explicitly. Not catching it is not considered an error public void f() { try { illegal(); } catch (IllegalArgumentException e) { // Explicit catch! doSomething(); } } 

我希望这会让事情更清楚……

  1. 不是。所有exception都在运行时发生。 已检查的exception是强制调用者处理它们或声明它们的exception。 它们通常用于发出可恢复的错误信号,这些错误不是由程序员错误(如文件不存在或网络连接问题)引起的。 运行时exception通常用于表示不可恢复的错误。 它们不会强制调用者处理或声明它们。 其中许多确实发出编程错误信号(如NullPointerException)。

  2. 因为这就是JLS如何定义未经检查的exception:一个exception是或扩展RuntimeException,它本身扩展了Exception。 使用单个inheritance根允许在单个catch子句中处理每个可能的exception。

关于你的例子:是的,throws子句是​​必需的,因为IOException是一个经过检查的exception,并且方法中的代码很容易抛出一个。

编译器只确保一个方法如果没有声明它就不能抛出一个已检查的exception。 一般认为,编译器的这种检查应该针对发生在程序员控制范围之外的exception,例如您引用的示例(数据库连接,文件丢失等)。 未经检查的exception“不应发生”,因此编译器不会强制您声明它们。

至于模拟IOException或任何其他,它是微不足道的:

 throw new IOException(); 

在您的示例中, prompt方法可能会抛出IOException ,这就是它需要声明它的原因。 这与您在调用方法时处理exception的方式无关。

RuntimeExceptionException的子类,可以方便地使用一个catch Exception子句捕获所有exception。 这可能是不同的设计; Java的exception类层次结构很乱。

如果您不在此处放置throws子句,则会发生此错误

ThrowsDemo.java:5:未报告的exceptionjava.io.IOException; 必须被捕获或被唤醒才能被抛出return(char)System.in.read();

所以抛出必要的条款。

已检查exception和未经检查的exception的五个示例。

 Unchecked Exception -- NullPointerException -- ArrayIndexOutofBound -- IllegalArgument Exception -- ClassCastException -- IllegalStateException -- ConcurrentModificationException Checked Exception Five Example -- FileNotFoundException -- ParseException -- ClassNotFoundException -- CloneNotSupportException -- SQLException 

已检查和未检查的例外情况

有两种类型的例外:已检查的例外和未经检查的例外。 已检查和未检查的exception之间的主要区别在于,在编译时检查已检查的exception,而在运行时检查未经检查的exception。

请阅读这篇文章以获得一个清晰的想法。

更多细节

当客户端代码可以根据exception信息采取一些有用的恢复操作时,使用已检查的exception。 客户端代码无法执行任何操作时,请使用未经检查的exception。 例如,如果客户端代码可以从中恢复并将SQLException转换为未检查(即RuntimeException)exception(如果客户端代码无法对其执行任何操作),则将SQLException转换为另一个已检查的exception。