小编典典

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

java

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

public void throwsOrNotThrowsThatsTheQuestion() {
    try {

        // Any processing

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

阅读 219

收藏
2020-09-08

共1个答案

小编典典

仅在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;
  }
}
2020-09-08