“空语句”可能(不)抛出哪些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的哪些子类不会出现在这些语句之间?


到目前为止我所知道的是InternalErrorOutOfMemoryErrorStackOverflowErrorUnknownError

这个问题与您发布的其他问题非常相似。 我想我会尝试在这里解决这两个问题。

既然你提到了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仅在以下情况下发生:

  • 调用ThreadThreadGroup类的(不推荐的) stop方法。

    一个线程可以调用(不推荐使用的) stop方法来影响另一个线程或指定线程组中的所有线程。 它们是异步的,因为它们可能在执行其他线程或线程的任何时刻发生。

  • Java虚拟机中的内部错误或资源限制,阻止它实现Java编程语言的语义。 在这种情况下,抛出的异步exception是VirtualMethodError的子类的实例。

但同样,没有必要关心这种类型的exception( VirtualMethodError子类),因为它们代表了JVM执行中的严重错误。 例如,可能是由于用户使用Ctrl + C手动中断。 在这种情况下,你无能为力。

如果您不执行任何指令,则VM不太可能请求内存或用尽当前线程的堆栈空间。 由于其他exception可能因为VM中的任何一种状态都UnknownError而被抛出,我想你应该总是期望发生InternalErrorUnknownError 。 因此,您不应该捕获Throwable而是Exception因为您不可能从错误中恢复 – 除非您正在创建自己的框架。