24

在下面的源代码中,我重新抛出一个Exception.
为什么不需要将throws关键字放在方法的签名上?

public void throwsOrNotThrowsThatsTheQuestion() {
    try {

        // Any processing

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

6 回答 6

33

此行为似乎只发生在 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>

...直到我真正投入了一个Exceptiontry

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,而 1.6 只是看到throw e;了类型Exception并为此给出了错误。

将其更改为 throw aRuntimeException使其按预期编译,因为与往常一样, unchecked 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;
  }
}
于 2013-11-11T19:22:09.280 回答
6

java.lang.Exception 是一个经过检查的异常,所以这将不起作用甚至编译。它可以与 unkeched (java.lang.RuntimeException) 一起使用。是否在 catch 块内抛出异常绝对没有区别。

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

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

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

于 2013-11-11T19:05:56.003 回答
3

如果你抛出一个检查异常,你需要把它放在抛出列表中

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

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

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

在此处阅读有关异常的更多信息。

于 2013-11-11T19:07:07.107 回答
3

为什么不需要将 throws 关键字放在方法的签名上?

你可以把它放出来,因为你// Any processing没有抛出任何check-exception

例子:

这个编译很好。

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 开始工作。在以前的版本中,抛出异常。更多信息在 java 7 中重新抛出

于 2013-11-11T19:07:31.903 回答
0

throw newException();是你永远不应该在 catch 块中做的事情,但你可能必须或想要做throw new SomeException(throwable);(保留完整的堆栈跟踪)而不是 throwthrowable;以符合你的方法的 API,例如当它声明抛出SomeException但您正在调用的代码可能会抛出IOException您不想添加到方法的 throws 子句中的代码。

可能最常见的情况是 new RuntimeException(throwable); 避免完全有 throws 子句。

于 2013-11-11T19:15:11.117 回答
0

当您将 throws 与方法一起使用时,这意味着将调用该方法的语句必须用 try catch 块包围。

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

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

希望这可以消除您的疑问。

于 2013-11-11T19:06:39.587 回答