So I've been brushing up on my Java skills as of late and have found a few bits of functionality that I didn't know about previously. Static and Instance Initializers are two such techniques.
My question is when would one use an initializer instead of including the code in a constructor? I've thought of a couple obvious possibilities:
static/instance initializers can be used to set the value of "final" static/instance variables whereas a constructor cannot
static initializers can be used to set the value of any static variables in a class, which should be more efficient than having an "if (someStaticVar == null) // do stuff" block of code at the start of each constructor
Both of these cases assume that the code required to set these variables is more complex than simply "var = value", as otherwise there wouldn't seem to be any reason to use an initializer instead of simply setting the value when declaring the variable.
However, while these aren't trivial gains (especially the ability to set a final variable), it does seem that there are a rather limited number of situations in which an initializer should be used.
One can certainly use an initializer for a lot of what is done in a constructor, but I don't really see the reason to do so. Even if all constructors for a class share a large amount of code, the use of a private initialize() function seems to make more sense to me than using an initializer because it doesn't lock you into having that code run when writing a new constructor.
Am I missing something? Are there a number of other situations in which an initializer should be used? Or is it really just a rather limited tool to be used in very specific situations?
Just to add to some already excellent points here. The static initializer is thread safe. It is executed when the class is loaded, and thus makes for simpler static data initialization than using a constructor, in which you would need a synchronized block to check if the static data is initialized and then actually initialize it.
versus
Don't forget, you now have to synchronize at the class, not instance level. This incurs a cost for every instance constructed instead of a one time cost when the class is loaded. Plus, it's ugly ;-)
Static initializers are useful as cletus mentioned and I use them in the same manner. If you have a static variable that is to be initialized when the class is loaded, then a static initializer is the way to go, especially as it allows you to do a complex initialization and still have the static variable be
final
. This is a big win.I find "if (someStaticVar == null) // do stuff" to be messy and error prone. If it is initialized statically and declared
final
, then you avoid the possibility of it beingnull
.However, I'm confused when you say:
I assume you are saying both:
and you are correct on the first point, wrong on the second. You can, for example, do this:
Also, when a lot of code is shared between constructors, one of the best ways to handle this is to chain constructors, providing the default values. This makes is pretty clear what is being done:
There is one important aspect that you have to consider in your choice:
Initializer blocks are members of the class/object, while constructors are not. This is important when considering extension/subclassing:
This means it is basically guaranteed that subclasses are initialized as intended by the parent class.
super()
[i.e. no parameters] implicitly or you have to make a specificsuper(...)
call manually.)This means it is possible that a implicit or exclicit
super(...)
call might not initialize the subclass as intended by the parent class.Consider this example of an initializer block:
output:
initializing in initializer block of: ChildOfParentWithInitializer init
-> No matter what constructors the subclass implements, the field will be initialized.
Now consider this example with constructors:
output:
Constructor of ChildOfParentWithConstructor inits to null null
-> This will initialize the field to
null
by default, even though it might not be the result you wanted.A static initializer is the equivalent of a constructor in the static context. You will certainly see that more often than an instance initializer. Sometimes you need to run code to set up the static environment.
In general, an instance initalizer is best for anonymous inner classes. Take a look at JMock's cookbook to see an innovative way to use it to make code more readable.
Sometimes, if you have some logic which is complicated to chain across constructors (say you are subclassing and you can't call this() because you need to call super()), you could avoid duplication by doing the common stuff in the instance initalizer. Instance initalizers are so rare, though, that they are a surprising syntax to many, so I avoid them and would rather make my class concrete and not anonymous if I need the constructor behavior.
JMock is an exception, because that is how the framework is intended to be used.
I read a whole article looking for an answer to the init order of initializers vs. their constructors. I didn't find it, so I wrote some code to check my understanding. I thought I would add this little demonstration as a comment. To test your understanding, see if you can predict the answer before reading it at the bottom.
Output:
I would also like to add one point along with all the above fabulous answers . When we load a driver in JDBC using Class.forName("") the the Class loading happens and the static initializer of the Driver class gets fired and the code inside it registers Driver to Driver Manager. This is one of the significant use of static code block.