我希望以下代码引发编译时错误throw t;,因为main没有声明抛出Throwable,但它成功编译(在Java 1.7.0_45中),并产生你期望它的输出,如果编译时错误是固定.
public class Test {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch(Throwable t) {
System.out.println("Caught "+t);
throw t;
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果Throwable更改为,它也会编译Exception.
这不会按预期编译:
public class Test {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch(Throwable t) {
Throwable t2 = t;
System.out.println("Caught "+t2);
throw t2;
}
}
}
Run Code Online (Sandbox Code Playgroud)
这编译:
public class Test {
public static void main(String[] args) {
try {
throwsRuntimeException();
} catch(Throwable t) {
System.out.println("Caught "+t);
throw t;
}
}
public static void throwsRuntimeException() {
throw new NullPointerException();
}
}
Run Code Online (Sandbox Code Playgroud)
这不是:
public class Test {
public static void main(String[] args) {
try {
throwsCheckedException();
} catch(Throwable t) {
System.out.println("Caught "+t);
throw t;
}
}
public static void throwsCheckedException() {
throw new java.io.IOException();
}
}
Run Code Online (Sandbox Code Playgroud)
这也编译:
public class Test {
public static void main(String[] args) throws java.io.IOException {
try {
throwsIOException();
} catch(Throwable t) {
System.out.println("Caught "+t);
throw t;
}
}
public static void throwsIOException() throws java.io.IOException {
throw new java.io.IOException();
}
}
Run Code Online (Sandbox Code Playgroud)
一个更复杂的示例 - 已检查的异常由外部catch块捕获,而不是声明为抛出.这编译:
public class Test {
public static void main(String[] args) {
try {
try {
throwsIOException();
} catch(Throwable t) {
System.out.println("Caught "+t);
throw t;
}
} catch(java.io.IOException e) {
System.out.println("Caught IOException (outer block)");
}
}
public static void throwsIOException() throws java.io.IOException {
throw new java.io.IOException();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,当编译器可以确定捕获的异常总是合法重新抛出时,似乎有一种特殊情况允许重新抛出异常.它是否正确?这在JLS中指定了哪里?还有其他像这样模糊不清的角落吗?
Mar*_*ers 10
JLS 11.2.2(强调我的)涵盖了这一点:
抛出语句表达式是catch子句C 的最终或有效最终异常参数的throw语句可以抛出异常类E iff:
E是一个异常类,声明C的try语句的try块可以抛出; 和
E的赋值与C的任何可捕获异常类兼容 ; 和
(......)
换句话说,Edoc中引用的类型是可以抛出的类型,而不是捕获它的catch子句参数的类型(可捕获的异常类).它只需要与catch子句参数兼容,但在分析中不使用参数的类型.
这就是为什么他们不遗余力地说出一个最终的或有效的最终异常参数 -如果t在你的例子中被重新分配,分析就会消失.