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

时间:2013-11-11 19:02:33

标签: java

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

public void throwsOrNotThrowsThatsTheQuestion() {
    try {

        // Any processing

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

6 个答案:

答案 0 :(得分:29)

此行为似乎仅在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(s)类型,其中1.6只看到了throw e;键入Exception并仅为此提供错误。

将其更改为抛出RuntimeException使其按预期编译,因为一如既往,未经检查的Exception不需要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引入了more inclusive type checking。引用...

  

考虑以下示例:

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;
  }
}

答案 1 :(得分:6)

java.lang.Exception是一个经过检查的异常,因此无法工作甚至编译。它可以使用unckeched(java.lang.RuntimeException)。 无论你是否在catch块中抛出异常,绝对没有区别。

编译器错误看起来像这样(取决于编译器):

  

java:未报告的异常java.lang.Exception;必须被抓住或宣布被抛出

编辑:如果你从未真正抛出异常,Java 7可以处理这种情况

答案 2 :(得分:3)

如果您检查了已检查的异常,则需要将其放在抛出列表中

public void retrhowChecked() throws Exception {
    try {
        throw new IOException();
    } catch(Exception e) {
        throw e;
    }
}

如果你抛出一个未经检查的异常,你不需要将它放在throws列表中,你可以使用它来在未经检查的异常中包装一个已检查的Exception,以避免在你更改有问题的方法时破坏使用此方法的代码以这种方式,它在更改后可能会产生一个检查异常。但你必须小心,检查Exception是否有待处理!

public void retrhowUnchecked() {
    try {
        throw new IOException();
    } catch(Exception e) {
        throw new RuntimeException(e);
    }
}

详细了解例外情况here

答案 3 :(得分:3)

  

为什么没有必要将throws关键字放在方法的上面   签名σ

您可以将// Any processing放弃任何已检查的例外

示例:

编译正常。

public void throwsOrNotThrowsThatsTheQuestion() {
    try {

        throw new RuntimeException();

    } catch (Exception e) {
        throw e;
    }

这将无法编译,您需要添加throws子句。

public void throwsOrNotThrowsThatsTheQuestion() {
    try {
        throw new Exception();
    } catch (Exception e) {
        //do something like log and rethrow
        throw e;
    }
}

这是自java 7以来的工作。在以前的版本中引发了异常。更多信息rethrow in java 7

答案 4 :(得分:0)

当你对方法使用throws时,这意味着调用该方法的语句必须用try catch块包围。

但是如果该方法已经包含了try catch块,则不需要使用thorws声明,因为该方法抛出的异常仅在那里处理。

调用此方法的语句不需要用try catch块包围。

希望这可以解除你的怀疑。

答案 5 :(得分:0)

  

抛出新的Exception();是你永远不应该做的事情   阻止,但您可能必须或想要执行throw new SomeException(throwable);(保留完整堆栈跟踪)   抛出throwable;以符合您方法的API,   例如当它声明抛出SomeException但你正在调用代码时   可能会抛出您不想添加的IOException   方法的抛出条款。

     

可能最常见的情况是新的RuntimeException(throwable);至   避免完全抛出投掷条款。