Static Initialization Blocks
If they weren't in a static initialization block, where would they be? How would you declare a variable which was only meant to be local for the purposes of initialization, and distinguish it from a field? For example, how would you want to write:
public class Foo {
private static final int widgets;
static {
int first = Widgets.getFirstCount();
int second = Widgets.getSecondCount();
// Imagine more complex logic here which really used first/second
widgets = first + second;
}
}
If first
and second
weren't in a block, they'd look like fields. If they were in a block without static
in front of it, that would count as an instance initialization block instead of a static initialization block, so it would be executed once per constructed instance rather than once in total.
Now in this particular case, you could use a static method instead:
public class Foo {
private static final int widgets = getWidgets();
static int getWidgets() {
int first = Widgets.getFirstCount();
int second = Widgets.getSecondCount();
// Imagine more complex logic here which really used first/second
return first + second;
}
}
... but that doesn't work when there are multiple variables you wish to assign within the same block, or none (e.g. if you just want to log something - or maybe initialize a native library).
The non-static block:
{
// Do Something...
}
Gets called every time an instance of the class is constructed. The static block only gets called once, when the class itself is initialized, no matter how many objects of that type you create.
Example:
public class Test {
static{
System.out.println("Static");
}
{
System.out.println("Non-static block");
}
public static void main(String[] args) {
Test t = new Test();
Test t2 = new Test();
}
}
This prints:
Static
Non-static block
Non-static block
Here's an example:
private static final HashMap<String, String> MAP = new HashMap<String, String>();
static {
MAP.put("banana", "honey");
MAP.put("peanut butter", "jelly");
MAP.put("rice", "beans");
}
The code in the "static" section(s) will be executed at class load time, before any instances of the class are constructed (and before any static methods are called from elsewhere). That way you can make sure that the class resources are all ready to use.
It's also possible to have non-static initializer blocks. Those act like extensions to the set of constructor methods defined for the class. They look just like static initializer blocks, except the keyword "static" is left off.
It's also useful when you actually don't want to assign the value to anything, such as loading some class only once during runtime.
E.g.
static {
try {
Class.forName("com.example.jdbc.Driver");
} catch (ClassNotFoundException e) {
throw new ExceptionInInitializerError("Cannot load JDBC driver.", e);
}
}
Hey, there's another benefit, you can use it to handle exceptions. Imagine that getStuff()
here throws an Exception
which really belongs in a catch block:
private static Object stuff = getStuff(); // Won't compile: unhandled exception.
then a static
initializer is useful here. You can handle the exception there.
Another example is to do stuff afterwards which can't be done during assigning:
private static Properties config = new Properties();
static {
try {
config.load(Thread.currentThread().getClassLoader().getResourceAsStream("config.properties");
} catch (IOException e) {
throw new ExceptionInInitializerError("Cannot load properties file.", e);
}
}
To come back to the JDBC driver example, any decent JDBC driver itself also makes use of the static
initializer to register itself in the DriverManager
. Also see this and this answer.