为什么我们不必将run-catch添加到RuntimeException?

我想问为什么我们不必将run-catch块添加到RuntimeException而我们应该使用其他exception?

我的意思是:

 public class Main { public static void main(String[] args) { throw new RuntimeException(); } } 

编辑:当我说: throw new RuntimeException(); 很明显会发生exception,为什么编译器不禁止这样做呢?

那是因为它是一个未经检查的例外。 它不需要显式声明或捕获。 另请参阅有关此主题的Sun教程 。

更新:通常,您应该只抛出一个RuntimeException (最好是在javadoc中列出的一个子类 )来表示调用者做错了。 即传递一个null参数(然后抛出NullPointerException ),或者一个非法参数(然后抛出IllegalArgumentException ),或者在错误的时刻/状态调用该方法(然后抛出IllegalStateException ),等等。 调用者应该修复他们的代码以避免这种情况。 例如,事先检查参数是否为null,或者参数的格式/语法是否正确,或确保在正确的时刻调用该方法。

如果存在应该抛出运行时exception并且不能使用其特定子类的特定情况,那么您应该扩展它并在新exception的javadoc和调用方法中正确记录它,例如ConfigurationException extends RuntimeException对于调用代码在使用前未正确配置应用程序/ API的情况。 这应该足以表明最终用户(另一个开发者)采取相应的行动。

简而言之: RuntimeExceptions应该识别由代码流或配置中的错误引起的可编程恢复问题(读取:开发人员的错误)。 Checked Exceptions应该识别程序可恢复的问题,这些问题是由代码控制之外的意外情况引起的(例如数据库关闭,文件I / O错误,错误的最终用户输入等)。 Errors应该以编程方式识别不可恢复的问题(例如,内存不足,初始化程序内的exception等)。

RuntimeExceptionError及其子类特别不是编译时检查的 – 它们不是方法的正式合同的一部分。

请参阅JLS中的第11章,例外,特别是11.2,exception的编译时检查。

  • JLS,Ch。 11,例外。

让我们这样说吧。 如果NullPointerException被设计为编译时exception怎么办? 如果这样做,编译器必须严格检查变量是否为null。 无法做到这一点。

 public void dummyMethod(Object obj){ } 

这里,编译器无法检查obj是否为null。 但是,当您有一个空指针场景时,必须抛出一些错误/exception。

根据语言规范, 在编译时检查 未经检查的exception ,这意味着编译器不需要捕获或指定(带有throws )它们的方法。 属于此类的类在第11.2节“ 编译时检查 JLS 例外 ”一节中详细说明:

未经检查的exception类RuntimeException类及其子类,以及类Error及其子类 。 所有其他exception类都是已检查的exception类 。 Java API定义了许多exception类,包括已检查和未选中的exception类。 程序员可以声明其他检查和未检查的exception类。 有关exception类层次结构的描述以及Java API和Java虚拟机定义的一些exception类,请参见第11.5节 。

因此,由于未经检查的exception中的RuntimeException ,编译器不会强制您处理它。 如果要强制一段代码的调用者处理exception,请使用已检查的exception(除RuntimeException之外的Exception的子类都是已检查的exception类)。

因为不禁止抛出运行时exception,也不必声明运行时exception。 您的程序是一个有效的Java程序,因此编译器没有理由抱怨。

基本上,未捕获的exception只是显示消息和终止应用程序的简写。

你为什么要这样做? 在某些情况下,您可以检测到某些内容出错,某些文件未加载,api丢失,某些数据因某种原因损坏,或者其他一百万个错误。 如果你不抛出exception,应用程序可能只是在另一个点崩溃,或者在最坏的情况下,在错误升级时继续运行,这使得调试变得更加困难。

重要的是要理解一个抛出exception因为有错误,exception不是错误,它只是信使。

这个论坛上的大多数答案一直在谈论exception层次结构和Java编译器没有捕获它们,但我会尝试从设计角度更多地回答这个问题,为什么事情的设计可能就像这样。

基本上当你调用一个函数(或写一些代码)时,可以根据三种不同的情况抛出exception:

  1. 基于不可避免的条件,例如网络不可用或文件系统上缺少某些预期文件。

  2. 基于可避免但已知的条件,Integer.parseInt(String)可以抛出NumberFormatException如果调用者传递一个不可转换的字符串,如"Hello" ,但调用者可以确保在将任何字符串传递给函数之前进行适当的validation并完全取消有可能产生exception。 一个常见的用例可能是在将网页传递给更深层进行转换之前validation网页上的表单字段age

  3. 一个未知或意外的情况任何时候某些代码行都会在你的代码中引发一个exception,因为你做了一些错误,并且在生产中爆发之前没有观察到错误情况,通常会发生NullPointer ReferenceIndexOutOfBounds等,如果观察到可能属于第2类。

类别1的例外通常被设计为Checked Exceptions因为它需要强制检查不可避免的错误条件,并强制执行它们的后备。 例如,IOException被检查exception,因为如果你打开一个文件,可能会有很多可能出错的东西(比如文件可能被删除,权限等),并且预先validation所有这些可能非常麻烦。

第二种类型的exception通常被建模为Unchecked Exceptions因为您可能已经进行了预先validation,并且在您已经处理过的情况下被强制使用try和catch可能会令人恼火。

第三种类型的例外通常不必担心,因为您不能将error handling放在可能意外出现的每个应用程序代码语句中。 但有时你可以在调用堆栈中放置一个全局处理程序,几乎所有的应用程序代码都在这里执行,并以通用方式处理它,这样你的应用程序就不会因意外错误而崩溃。

例如,如果您正在运行Web应用程序,则可以将Servlet容器配置为针对应用程序中的任何未处理错误发送通用500 Internal Server Error 。 或者,如果您运行的是独立的Java应用程序,则可以将main method的内容保存在try catch块中,以防止崩溃应用程序。