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

抛出异常:为什么在没有throws子句的情况下编译方法?

蒋永宁
2023-03-14
问题内容

在下面的源代码中,我抛出一个Exception
为什么没有必要将throws关键字放在方法的签名上?

public void throwsOrNotThrowsThatsTheQuestion() {
    try {

        // Any processing

    } catch (Exception e) {
        throw e;
    }
}

问题答案:

仅在Java 1.7上会出现此现象。使用1.6进行编译时,出现以下编译器错误消息:

c:\dev\src\misc>javac -source 1.6 Main.java
warning: [options] bootstrap class path not set in conjunction with -source 1.6
Main.java:22: error: unreported exception Exception; must be caught or declared
to be thrown
        throw e;
        ^
1 error
1 warning

但是,使用Java 1.7可以编译。

c:\dev\src\misc>javac -source 1.7 Main.java

c:\dev\src\misc>

…直到我实际把一个块扔了Exception进去try

public static void throwsOrNotThrowsThatsTheQuestion() {
try {

    // Any processing
    throw new IOException("Fake!");

} catch (Exception e) {
    throw e;
}

编译中…

c:\dev\src\misc>javac -source 1.7 Main.java
Main.java:22: error: unreported exception IOException; must be caught or declare
d to be thrown
        throw e;
        ^
1 error

看起来Java 1.7足够聪明Exception,可以通过分析try块代码来检测可能抛出throw e;的类型,而1.6刚看到类型Exception并为此给出了错误。

对其进行更改以RuntimeException使其按预期方式进行编译,因为与往常一样,未经检查的Exceptions不需要throws子句:

public static void throwsOrNotThrowsThatsTheQuestion() {
try {

    // Any processing
    throw new RuntimeException("Fake!");

} catch (Exception e) {
    throw e;
}

编译中…

c:\dev\src\misc>javac -source 1.7 Main.java

c:\dev\src\misc>

说明

这是怎么回事:

Java
7引入了更多的包容性类型检查。报价…

考虑以下示例:

static class FirstException extends Exception { }
static class SecondException extends Exception { }

public void rethrowException(String exceptionName) throws Exception {
  try {
    if (exceptionName.equals("First")) {
      throw new FirstException();
    } else {
      throw new SecondException();
    }
  } catch (Exception e) {
    throw e;
  }
}

本示例的try块可能抛出FirstException或SecondException。假设您要在rethrowException方法声明的throws子句中指定这些异常类型。在Java
SE
7之前的版本中,您不能这样做。因为catch子句e的异常参数是Exception类型,并且catch块重新抛出了异常参数e,所以只能在rethrowException方法声明的throws子句中指定异常类型Exception。

但是, 在Java SE
7中,可以在rethrowException方法声明的throws子句中指定异常类型FirstException和SecondException

。Java SE 7编译器可以确定语句throw
e引发的异常必须来自try块,而try块引发的唯一异常可以是FirstException和SecondException。即使catch子句e的异常参数是Exception类型,编译器仍可以确定它是FirstException或SecondException的实例:

(强调我的)

public void rethrowException(String exceptionName)
throws FirstException, SecondException {
  try {
    // ...
  }
  catch (Exception e) {
    throw e;
  }
}


 类似资料:
  • 我想知道为什么java编译器允许在方法声明中抛出,而方法永远不会抛出异常。因为“throws”是处理异常的一种方式(告诉调用方处理它)。 因为有两种处理异常的方法(抛出和try/catch)。在try/catch中,它不允许捕获try块中未抛出的异常,但它允许在不抛出异常的方法中抛出。

  • 问题内容: 如果有一些代码显然不能引发异常,则Java编译器似乎不一致,而您编写的周围代码声明该代码可以引发该异常。 考虑这些代码片段。 片段1 一个是永远不会抛出异常。 是带信息的编译错误 片段2 表示从未抛出的异常的声明。 它编译良好。 因此,第一个代码段的结果表明,编译器可以计算方法是否可以引发列表中列出的异常。因此,似乎编译器 故意 不报告第二个片段的错误。但为什么?为什么即使编译器知道无

  • 问题内容: 我偶然发现该语句(从一些更复杂的代码中摘录)进行编译: 在短暂但快乐的时刻,我认为受检查的异常最终决定已经死亡,但是对此仍然感到遗憾: 该块不必为空;似乎可以有代码,只要该代码不引发检查异常即可。这似乎是合理的,但是我的问题是,语言规范中的哪个规则描述了此行为?据我所知,§14.18throw语句明确禁止使用它,因为表达式的类型是已检查的异常,并且不会被捕获或声明为被抛出。(?) 问题

  • 我正在编写一个spring-mvc应用程序(并学习spring-mvc)。我没有向pom.xml添加servlet依赖项。当我运行或时,它会成功地完成。不是应该抛出类似“can not find javax.servlet.http.HttpServlet”这样的异常吗?它是如何编译的?

  • 问题内容: 我今天在浏览一些日志时遇到一个奇怪的错误。 它在日志中的显示方式如下: 代码如下所示: 如果重要的话,代码位于jsp中。再次在日志中重复相同的异常(正如您期望的那样)。 我没有任何原因的记录-日志中的上一行显示了查询的执行。在4天的时间内仅发生了两次,似乎并未对系统造成任何损害。 环境:在Java 5的Tomcat下运行的非常繁忙的Web服务。 我并没有要求调试系统的提示-这些错误已久

  • 我刚刚通过nodejs.org上的软件包安装了node和npm,每当我试图搜索或安装npm时,它都会抛出以下错误,除非我执行该命令。我觉得这是一个权限问题?我已经是管理员了。