在下面的源代码中,我抛出一个Exception。 为什么没有必要将throws关键字放在方法的签名上?
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:
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并为此给出了错误。
throw e;
对其进行更改以RuntimeException使其按预期方式进行编译,因为与往常一样,未经检查的Exceptions不需要throws子句:
RuntimeException
public static void throwsOrNotThrowsThatsTheQuestion() { try { // Any processing throw new RuntimeException("Fake!"); } catch (Exception e) { throw e; }
说明
这是怎么回事:
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的实例:
本示例的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; } }