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
.
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
The compiler will probably remove the code that contains "nothing" or empty statements from the bytecode. The equivalent in the bytecode would be exactly similar to:
// ....
A(); B(); C();
D(); E(); F();
G(); H(); I();
J(); K(); L();
// ....
Of course during the execution, any kind of unexpected Error
(like UnknownError
) could occur and it's normally not expected to handle it in your application.
The closest kind of exception that could occur anywhere (emphasized in order to possibly cover the time between two bytecode instructions) is asynchronous exceptions:
Most exceptions occur synchronously as a result of an action by the thread in which they occur, and at a point in the program that is specified to possibly result in such an exception. An asynchronous exception is, by contrast, an exception that can potentially occur at any point in the execution of a program.
Asynchronous exceptions occur only as a result of:
An invocation of the (deprecated) stop
method of class Thread
or ThreadGroup
.
The (deprecated) stop
methods may be invoked by one thread to affect another thread or all the threads in a specified thread group. They are asynchronous because they may occur at any point in the execution of the other thread or threads.
An internal error or resource limitation in the Java Virtual Machine that prevents it from implementing the semantics of the Java programming language. In this case, the asynchronous exception that is thrown is an instance of a subclass of VirtualMethodError
.
But again, there is no point to care about this type of exceptions (subclasses of VirtualMethodError
) because they represent a serious error in the JVM execution. For example, it may be due to a manual interruption by the user using Ctrl+C. In this case, there's not much you can do about it.
If you don't execute any instruction then the VM is unlikely to request memory or run out of stack space for the current thread. As the other exceptions could be thrown because any kind of state in the VM is out of kilt, I guess you should always expect InternalError
or UnknownError
to occur. Hence you should not catch Throwable
but Exception
as it is unlikely you can recuperate from the error - unless you are creating your own framework maybe.