当前位置: 首页 > 面试题库 >

是否需要抛出异常而抛出异常?

谷星文
2023-03-14
问题内容

考虑以下代码:

static void main(String[] args) {
  try {
  } catch (Exception e) {
    throw e;
  }
}

无需添加throws Exception方法签名即可编译该代码。(它与同样表现Throwable到位Exception,太)。

我理解为什么 可以 安全地运行它,因为Exception实际上不能将其引发在try块中,因此不能引发已检查的异常。我有兴趣知道在何处指定此行为。

并非throw e永远都不会达到目标:以下代码也会编译:

static void stillCompilesWithThrownUncheckedException() {
  try {
    throw new NullPointerException();
  } catch (Exception e) {
    throw e;
  }
}

但是,如果抛出一个检查的异常,它不会像我期望的那样编译:

static void doesNotCompileWithThrownCheckedException() {
  try {
    throw new Exception();
  } catch (Exception e) {
    throw e;  // error: unreported exception Exception; must be caught or declared to be thrown
  }
}

在JLS Sec
11.2.2中
,它说:

throw,其抛出的表达式语句(§14.18)具有静态类型E和不是最终或有效最终异常参数可以抛出E或任何异常类,抛出的表达可以抛出。

我对此声明的解释是throw e可以抛出Exception,因为的静态类型eException。然后,在JLS Sec 11.2.3

如果方法或构造函数主体可以抛出某些异常类E(当E为检查的异常类,并且E不是方法或构造函数的throws子句中声明的某个类的子类),则这是编译时错误。

但这不是前两种情况下的编译时错误。语言规范在哪里描述了这种行为?

编辑:将其标记为欺骗后,我要问一个后续问题: 在第一个示例中 为什么不throw e;认为它不可达

在JLS Sec
14.21中
更容易找到答案:

  • 如果满足以下两个条件,则可以到达catch块C:

    * C的参数类型是未经检查的异常类型或Exception,或者是Exception的超类,或者try块中的某些表达式或throw语句是可到达的,并且可以引发其类型可以分配给C的参数类型的受检查的异常。(如果包含表达式的最里面的语句是可到达的,则该表达式是可到达的。)

有关表达式的正常和突然完成,请参见§15.6。

* 在try语句中没有较早的catch块A,以使C的参数类型与A的参数类型相同或成为其子类。

这两个都是正确的(它是type
Exception,并且没有较早的catch块),因此它是“可到达的”。我猜想try对于这种微不足道的构造,调用空块作为特殊情况的工作量太大了。


问题答案:

我相信第11.2.2节的下一段回答了这个问题:

如果一条throw语句的抛出表达式是catch子句C的最终异常参数或实际上是最终异常参数,则该语句可以引发异常类E iff:

  • E是一个异常类,声明C trytry语句的块可以抛出该异常类;和


因此,throw e;“只能抛出”相应try块“可以抛出”的异常,后者由try-block中的实际语句定义。

显然,空的try-block不符合任何异常类的“可以抛出”的条件。您的第二个示例“可以抛出”
NullPointerException,并且由于catch块只能抛出try块“可以抛出”的异常,因此catch块也只能抛出未经检查的NullPointerException。

第三个示例的try块“可以抛出” java.lang.Exception本身,因此catch块“可以抛出”
java.lang.Exception,因此必须捕获或声明要抛出java.lang.Exception。



 类似资料:
  • 抛出异常的行为是否可能抛出不同的异常? 为了抛出异常,必须(可选地)分配新对象,并调用其构造函数(隐式调用fillinstacktrace)。在某些情况下,听起来像addSupressed也被称为。那么如果没有足够的内存会发生什么呢?JVM是否需要预分配内置异常?例如,(1/0)会抛出OutOfMemoryError而不是ArithmeticException吗? 此外,构造函数是一个方法调用,因

  • 问题内容: 我试图在Netbeans中重构一个大型程序,但我有点迷茫。我从来没有非常模块化,但是现在通过实际学习如何做到这一点来尝试纠正这种情况,并在将来纠正这种情况。不幸的是,我在将某些教程翻译成我的程序时遇到了麻烦。所以我希望这里有人可以帮忙。目前,我正在尝试分解一部分采用特定格式的文件并制成表格的代码。我知道我需要创建一个类并使用它来创建表对象,但是我不确定如何做。我有一个主文件,用于获取文

  • 问题内容: 我目前正在使用play2框架。 我有几个正在抛出的类,但是play2s全局处理程序使用throwable而不是异常。 例如我的一门课是抛出一个。我是否可以检查可抛物体(如果是)? 问题答案: 您可以使用它来检查它是否存在。 例: 假设是参考。

  • throw 关键字表示发生了异常,称为抛出异常。throw 通常指定一个操作数(我们将介绍不指定操作数的特殊情况)。throw 的操作数可以是任何类型,如果操作数是个对象,则称为异常对象。也可以抛出条件表达式而不是抛出对象,可以抛出不用于错误处理的对象。 抛出异常时,指定相应类型的最近一个异常处理器(对抛出该异常的try块)捕获这个异常。try块的异常处理紧接在try块后面。 抛出异常时,生成和初

  • 在你可以捕获异常之前,一些代码必须抛出一个异常。任何代码都可能会抛出异常:您的代码,来自其他人编写的包(例如Java平台附带的包)或Java运行时环境的代码。无论是什么引发的异常,它总是通过 throw 语句抛出。 您可能已经注意到,Java平台提供了许多异常类。所有类都是Throwable类的后代,并且都允许程序区分在程序执行期间可能发生的各种类型的异常。 您还可以创建自己的异常类来表示在您编写

  • 所以我正在尝试重构以下代码: 我想出了下面的开头: 但是,它不编译(显然),因为不能抛出。有什么方法可以将它添加到的方法声明中吗? 还是只有这样才能做到? 更新后,我才意识到接口非常简单,因为它只有方法。我扩展的最初原因是优先于基本功能,例如默认方法。