Search code examples
javaoperating-systemjvmvirtual-machinejls

Which Java Errors and Exceptions may (not) be thrown by "empty statements"?


Which subclass(es) of java.lang.Throwable may be thrown by an empty statement?

By the phrase "an empty statement", I'm referring to the "nothing", the "semi-colon", and the "semi-colons":

// ....
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();
// ....

Which subclasses of Throwable may be thrown between A(); and B(); or between C(); and D(); or between F(); and G(); or between I(); and J();?

Or rather, which subclasses of Throwable are guaranteed not to appear between those statements?


The ones I know so far is the InternalError, the OutOfMemoryError, the StackOverflowError, and the UnknownError.


Solution

  • This question is very similar to the other question you posted. I think I'll try to address both questions here.

    Since you refer to the JVMS I'll assume that you're after a formal answer, and the formal answer is that your question(s) doesn't really make sense. :-)

    Asking how the JVM will execute a snippet of Java source code is like asking a mathematician the correct way of computing 10+10. The mathematician will probably say something like "how to compute it is not defined". Similarly, the JLS that defines the meaning of the Java snippet does not go into specifics of how to execute it.

    So, first let me formalize your question slightly: "Where in the bytecode (emitted by the reference implementation of javac) corresponding to the given Java snippets could VirtualMachineErrors occur?"

    This question is arguably much simpler to answer. The relevant section of the JVMS says

    A Java Virtual Machine implementation throws an object that is an instance of a subclass of the class VirtualMethodError when an internal error or resource limitation prevents it from implementing the semantics described in this chapter. This specification cannot predict where internal errors or resource limitations may be encountered and does not mandate precisely when they can be reported.

    Thus, the answer is: Between any two bytecode instructions.

    Now to return to your original question: This snippet for instance

    try {
         // nothing
    } catch (java.lang.Throwable e) {
         // which Throwable subclass might we see?
    }
    

    is compiled to the empty program, which can't reasonably throw any exceptions.


    Regarding your follow up question in a comment:

    Should JLS 11.1.3 be read as "subclasses of Throwable are guaranteed not to appear between bytecode unless it is a subclass of VirtualMachineError"?

    Yes, you could put it like that. I would perhaps have worded it a bit differently: Any instruction can give rise to

    • the exceptions specified by the JVM Instruction set for the instruction in question,
    • any exception of type VirtualMachineError
    • and no other exceptions