All Java code runs in the context of a thread. The linked JavaDoc explains the error handling and exit criteria, but here is the gist of it:
- The JVM spins itself up and prepares the execution environment.
- The JVM creates a thread which will run the
main() method using whatever command-line parameters are applicable.
- The JVM sets a default uncaught exception handler that prints the exception to standard error and terminates.
- The JVM executes the thread.
In the case of an uncaught exception, the program effectively dies per the third item above. This behavior is further specified in the Java Language Specification, Section 11.3
Others have mentioned static blocks and how they execute before
main(). However, this requires a bit more explanation to understand correctly.
When loading a class, the class loader must initialize all
static final state and run all
static blocks before the class can be used, to include instantiating instances of the class (aside: create a Java class where a class constant is initialized in a static block after creating an instance of the class, and the constructor references the constant. Boom!). However, this all happens in the class loader logic before any code can reference the class. Furthermore, the class is loaded in whatever thread referenced the class.
What this means is if the class containing
main() references another class (e.g. class constant) then that class must be loaded before
main() executes to include its static blocks. Otherwise, the static blocks are executed as above. If the class fails to load, then the class containing
main() will also fail to load and the program will terminate.
Another FYI: static blocks can throw.
Errors are thrown as-is.
Exceptions are forbidden (compile-time error).
RuntimeExceptions are wrapped in ExceptionInInitializerError. These are handled per the uncaught exception handler, which will typically either kill the thread or the application (main thread) unless you carefully wrap the class reference (and loading) in a