◎위챗 : speedseoul
https://airbrake.io/blog/java/exceptionininitializererror
Moving along through our in-depth Java Exception Handling series, today we’ll dive into the ExceptionInInitializerError, which is thrown when an error occurs within the static initializer
of a class or object. Since an ExceptionInInitializerError
isn’t ever the cause of a thrown error, catching such an exception provides an underlying causal exception
that indicates what the actual source of the issue was.
Throughout this article we’ll examine the ExceptionInInitializerError
by looking at where it resides in the overall Java Exception Hierarchy. We’ll then explore a simple and fully-functional code sample that illustrates how a static initializer works, and what might lead to a thrown ExceptionInInitializerError
in such an initializer, so let’s get to it!
All Java errors implement the java.lang.Throwable
interface, or are extended from another inherited class therein. The full exception hierarchy of this error is:
java.lang.Object
java.lang.Throwable
java.lang.Error
java.lang.LinkageError
ExceptionInInitializerError
Below is the full code sample we’ll be using in this article. It can be copied and pasted if you’d like to play with the code yourself and see how everything works.
Since the appearance of an ExceptionInInitializerError
indicates a problem within a static initializer
, we should briefly examine what a static initializer is and how they’re typically used. Put simply, a static initializer block is a normal code block that is executed when the class is loaded.
A static initializer is created by enclosing code anywhere inside a class definition surrounded by braces ({
& }
) and also preceded by the static
keyword. For example:
As you can see in the code above, there can be as many static initializer blocks as desired within a class definition. Each will be executed in a top-down manner when the class is first loaded.
Static initializers are not to be confused with instance initializers
(or instance members
), which are executed when the class is instantiated (i.e. a new object of that class type
is created). Instance initializers are also executed just before the constructor
method.
An instance initializer is written inside a class definition using two braces ({
& }
), but without a preceding static
keyword:
Just as with static versions, multiple instance initializers can be defined and will be executed from top to bottom.
The purpose of a static initializer is typically to execute any initialization code that must occur before a class can be used. Critically, static initializers are only executed once ever, the first time that class is loaded. Thus, they are great for classes that are frequently used throughout the application, but only need some basic configuration code to be executed once before multiple instances are used elsewhere, such as a database connection class.
To test a static initializer in “real” code we’ve added a simple snippet and field to our trusty Book
class:
A static initializer block has been added near to the top of the class definition, and merely attempts to ensure the publicationType
static field is an upper case value:
With this static initializer in place let’s try creating a new Book instance:
Executing this main(String[] args)
method produces the following output:
Sure enough, this threw an ExceptionInInitializerError
at us. Just as importantly, since ExceptionInInitializerErrors
aren’t ever going to cause a problem themselves, catching such an exception always contains an actual causal exception
, which is the error that was thrown within a static initializer that led to the caught ExceptionInInitializerError
. In this case, we see the cause was a NullPointerException
. With a bit of digging and consideration, we can see that the problem is within the static initializer code inside the Book
class. It attempts to get the static publicationType
value, but we don’t explicitly set an initial value for this field, so calling this references a null
value, hence the NullPointerException
. The solution is to either set an initial value for publicationType
, or to include a try-catch
block within the static initializer. In this case, a try-catch
block handles the error, but doesn’t resolve the root cause, so it’s probably better to specify a default value instead:
Now, rerunning the same main(String[] args)
method instantiates our Book
just fine and outputs the results:
A few things worth noting. First, since our code to force the publicationType
value to be upper case occurs within a static initializer, this occurs before our Book
instance is initialized, as well as before the Book(String title, String author, Integer pageCount, Date publishedAt, String publicationType)
constructor
method is executed. Thus, even though we successfully change the publicationType
from the default of Book
to novel
, it won’t be upper case’d unless we do so inside an instance
or member initializer
.
Additionally, since publicationType
is a static
field, this means it is unique to the entire Book
class. If we were to create a second Book
instance with a publicationType
specified in the constructor of poem
, the publicationType
of our Game of Thrones
Book
instance would also have its publicationType
changed to poem
:
This code produces the following output:
As we can see, the publicationType
of both instances is now the new value of poem
, so just be ware that static
members and initializers are global to all instances of a particular class.
The Airbrake-Java library provides real-time error monitoring and automatic exception reporting for all your Java-based projects. Tight integration with Airbrake’s state of the art web dashboard ensures that Airbrake-Java
gives you round-the-clock status updates on your application’s health and error rates. Airbrake-Java
easily integrates with all the latest Java frameworks and platforms like Spring
, Maven
, log4j
, Struts
, Kotlin
, Grails
, Groovy
, and many more. Plus, Airbrake-Java
allows you to easily customize exception parameters and gives you full, configurable filter capabilities so you only gather the errors that matter most.
Check out all the amazing features Airbrake-Java has to offer and see for yourself why so many of the world’s best engineering teams are using Airbrake to revolutionize their exception handling practices!