Недавно обнаружил и сообщил о факте, что можно пропустить проверенное исключение через javac-компилятор и выбросить его там, где его не нужно бросать. Это компилируется и запускается на Java 6 и 7, бросая предложение SQLException
без throws
или catch
:
public class Test {
// No throws clause here
public static void main(String[] args) {
doThrow(new SQLException());
}
static void doThrow(Exception e) {
Test.<RuntimeException> doThrow0(e);
}
static <E extends Exception> void doThrow0(Exception e) throws E {
throw (E) e;
}
}
Сгенерированный байт-код указывает, что JVM действительно не заботится о проверенных/непроверенных исключениях:
// Method descriptor #22 (Ljava/lang/Exception;)V
// Stack: 1, Locals: 1
static void doThrow(java.lang.Exception e);
0 aload_0 [e]
1 invokestatic Test.doThrow0(java.lang.Exception) : void [25]
4 return
Line numbers:
[pc: 0, line: 11]
[pc: 4, line: 12]
Local variable table:
[pc: 0, pc: 5] local: e index: 0 type: java.lang.Exception
// Method descriptor #22 (Ljava/lang/Exception;)V
// Signature: <E:Ljava/lang/Exception;>(Ljava/lang/Exception;)V^TE;
// Stack: 1, Locals: 1
static void doThrow0(java.lang.Exception e) throws java.lang.Exception;
0 aload_0 [e]
1 athrow
Line numbers:
[pc: 0, line: 16]
Local variable table:
[pc: 0, pc: 2] local: e index: 0 type: java.lang.Exception
JVM принимает это одно. Но у меня есть некоторые сомнения в том, должен ли Java-язык. Какие части JLS оправдывают это поведение? Это ошибка? Или хорошо скрытая "функция" языка Java?
Мои чувства:
-
doThrow0()
<E>
привязан кRuntimeException
вdoThrow()
. Следовательно, вdoThrow()
не требуется предложениеthrows
в строках JLS §11.2. -
RuntimeException
совместим с назначением сException
, поэтому никакой компилятор (который приведет к созданиюClassCastException
) не будет сгенерирован компилятором.