“空语句”可能(不)抛出哪些Java错误和exception?
可以通过空语句抛出java.lang.Throwable
哪个子类?
用“空话”这句话,我指的是“没有”,“分号”和“半冒号”:
// .... A(); B(); C(); try { // nothing } catch (java.lang.Throwable e) { // which Throwable subclass might we see? } D(); E(); F(); try { ; // semi-colon } catch (java.lang.Throwable e) { // which Throwable subclass might we see? } G(); H(); I(); try { ; ; ;; ;;;;; ; ; ;;; ;; ;; ;; ;; ; ;; ; ;; // ... semi-colons } catch (java.lang.Throwable e) { // which Throwable subclass might we see? } J(); K(); L(); // ....
可以在A();
之间抛出哪些 Throwable子类A();
和B();
或者在C();
之间C();
和D();
或者在F();
之间F();
和G();
或者在I();
之间I();
和J();
?
或者更确切地说, 保证 Throwable的哪些子类不会出现在这些语句之间?
到目前为止我所知道的是InternalError
, OutOfMemoryError
, StackOverflowError
和UnknownError
。
这个问题与您发布的其他问题非常相似。 我想我会尝试在这里解决这两个问题。
既然你提到了JVMS,我会假设你正式回答,而正式答案是你的问题没有意义。 🙂
询问JVM 如何执行Java源代码片段就像向数学家询问计算10 + 10的正确方法一样。 数学家可能会说“ 如何计算它没有定义”。 类似地,定义Java代码段含义的JLS没有详细说明如何执行它。
所以,首先让我稍微正式化你的问题:“ 字节码 (由javac
的参考实现发出)在哪里对应于给定的Java片段可能会发生VirtualMachineErrors
?”
这个问题可以说要简单得多。 JVMS的相关部分说
当内部错误或资源限制阻止它实现本章中描述的语义时,Java虚拟机实现会抛出一个对象,该对象是类
VirtualMethodError
的子类的实例。 该规范无法预测可能遇到内部错误或资源限制的位置,并且无法准确地确定何时可以报告它们。
因此,答案是:在任何两个字节码指令之间。
现在回到原来的问题:例如这个片段
try { // nothing } catch (java.lang.Throwable e) { // which Throwable subclass might we see? }
被编译为空程序,不能合理地抛出任何exception。
关于您在评论中的后续问题:
是否应将JLS 11.1.3读作“
Throwable
子类保证不会出现在字节码之间,除非它是VirtualMachineError
的子类”?
是的,你可以这样说。 我可能会用不同的措辞:任何指令都可以产生
- JVM指令集为相关指令指定的exception,
-
VirtualMachineError
类型的任何exception - 没有其他例外
编译器可能会从字节码中删除包含“nothing”或空语句的代码。 字节码中的等价物将完全类似于:
// .... A(); B(); C(); D(); E(); F(); G(); H(); I(); J(); K(); L(); // ....
当然,在执行过程中,可能会出现任何类型的意外Error
(如UnknownError
),并且通常不会在应用程序中处理它。
可能在任何地方发生的最接近的exception(为了可能覆盖两个字节码指令之间的时间而强调)是异步exception :
大多数exception由于它们发生的线程的动作而同步发生,并且在程序中指定可能导致这种exception的点。 相反, 异步exception是可能在程序执行的任何时刻发生的exception。
异步exception仅在以下情况下发生:
调用
Thread
或ThreadGroup
类的(不推荐的)stop
方法。一个线程可以调用(不推荐使用的)
stop
方法来影响另一个线程或指定线程组中的所有线程。 它们是异步的,因为它们可能在执行其他线程或线程的任何时刻发生。Java虚拟机中的内部错误或资源限制,阻止它实现Java编程语言的语义。 在这种情况下,抛出的异步exception是
VirtualMethodError
的子类的实例。
但同样,没有必要关心这种类型的exception( VirtualMethodError
子类),因为它们代表了JVM执行中的严重错误。 例如,可能是由于用户使用Ctrl + C手动中断。 在这种情况下,你无能为力。
如果您不执行任何指令,则VM不太可能请求内存或用尽当前线程的堆栈空间。 由于其他exception可能因为VM中的任何一种状态都UnknownError
而被抛出,我想你应该总是期望发生InternalError
或UnknownError
。 因此,您不应该捕获Throwable
而是Exception
因为您不可能从错误中恢复 – 除非您正在创建自己的框架。