繁体   English   中英

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

[英]Why we don't have to add try-catch to a RuntimeException?

我想问一下为什么我们不必将 try-catch 块添加到RuntimeException而我们应该对其他异常这样做?

我的意思是:

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

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

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

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

如果存在应该抛出运行时异常的特定情况并且您不能使用其特定子类之一,那么您应该扩展它并在新异常的 javadoc 和调用方法中正确记录它,例如ConfigurationException extends RuntimeException对于调用代码在使用前没有正确配置应用程序/API 的情况。 这应该向最终用户(其他开发人员)发出足够的信号以采取相应的行动。

简而言之:

  • RuntimeExceptions应识别由代码流或代码开发人员控制下的配置中的错误引起的可通过编程恢复的问题(阅读:开发人员的错误)。
  • Checked Exceptions应识别由代码开发人员无法控制的意外情况(例如数据库关闭、文件 I/O 错误、最终用户输入错误等)引起的可通过编程方式恢复的问题。
  • Errors应该识别出代码开发人员无法控制的编程上不可恢复的问题(例如内存不足、初始化程序中的异常等)。

让我们这样争论。 如果 NullPointerException 被设计为编译时异常怎么办? 如果这样做,编译器必须严格检查变量是否为空。 没有办法做到这一点。

public void dummyMethod(Object obj){

}

这里编译器没有办法检查 obj 是否可以为空。 但是,当您遇到空指针场景时,必须抛出一些错误/异常。

RuntimeExceptionError和它们的子类特别不经过编译时检查——它们不是该方法正式契约的一部分。

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

根据语言规范,未检查异常不会在编译时检查,这意味着编译器不需要方法来捕获或指定(使用throws )它们。 属于此类别的类在第11.2编译时检查JLS 的异常中有详细说明:

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

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

这个论坛上的大多数答案都在谈论异常层次结构和 Java 编译器没有捕捉到它们,但我会尝试从设计的角度更多地回答这个问题,以及为什么事情是这样设计的。

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

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

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

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

类别 1 的异常通常被设计为Checked Exceptions因为它需要强制检查不可避免的错误情况,并强制执行它们的回退。 例如 IOException 是检查异常,因为如果您打开文件,可能会出现很多错误(例如文件可能被删除,权限等)并且预验证所有这些可能非常麻烦。

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

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

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

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

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

为什么你需要这样做? 在某些情况下,您可以检测到出现问题、某些文件未加载、API 丢失、某些数据由于某种原因损坏,或者其他一百万件事情中的一件出错了。 如果您不抛出异常,应用程序可能会在另一点崩溃,或者在最坏的情况下,在错误升级时继续运行,从而使调试变得更加困难。

理解抛出异常是因为存在错误很重要,异常不是错误,它只是信使。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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