Java is an OO language, which means much of the functionality of a Java application is encapsulated into cohesive classes that can be instantiated and acted upon. Nevertheless once in a while you end up with some functions that are applicable to more than one class. These functions don't really belong to any particular class but to a sub-system or a package. Although one can express this grouping as a class by itself represented by interfaces, it is just simpler to collect them as static functions in a class, when one doesn't need the sophistication of service-centric approach for these methods.
For example I have a class called ServletUtils:
public class ServletUtils
{
static public void
writeOutAsJavaScript(PrintWriter out, StringBuffer javaScript);
static public String
convertToHtmlLines(String inString);
static public Map
parseQueryString(String httpQueryString);
static public Map
getParameters(HttpServletRequest request);
static public String
getSusbstitutedURL(String encodedString, Map arguments);
//.. so on and so forth
}
One characteristic of static functions is that they are stateless, although for efficiency they may depend on some static variables. When these static variables are introduced or utilized you need to know the class initialization rules laid out by the language. Although these rules are fairly intuitive it is beneficial to know them in some depth, as static initialization result in side effects. This article is about what these side effects are and how to minimize them through a pattern called "Static Resource Holder". With that in mind I want to first review the basics of static initialization rules. For a complete treatment of the rules refer to the java language specification links at the end of the article.
While reviewing the static initialization behavior I ran into an interesting piece of code involving a name resolution and a static variable. Under this scenario accessing a static variable of a class through one of its subclass namespace will not initialize the subclass as one might rightly or wrongly expect but only initialize the super class.
Consider the following super class with a static variable defined in it. There is no magic in this class. A static variable and a static block, perhaps completely unrelated to each other.
class superClass
{
public static int i=10;
static
{
System.out.println("Super class initialized");
}
}
In addition to demonstrating the odd fact, the code above also demonstrates the basic syntax of a static block of code. Notice how bare it is in its structure only demarcated by the "static" key word. Also notice that there are no returns in the code block nor any exceptions. Nevertheless it is quite alright to throw run time exceptions. Now let us try to access that static variable "i" and see what happens. To test this out let me define a simple "Test" class with a "main" in it that makes use of the variable "i".
public class Test
{
public static void main(String[] args)
{
System.out.println("Accessing static i:" + superClass.i);
}
}
When executed the Test class will produce
Super class initialized
Accessing static i:10
See how the intended print line "Accessing static i:10" shows up after the "Super class initialized" print statement. This is a typical behavior of the static initialization. The 101 of side effects. Now let me introduce a sub class and access the same static variable through the scope of the sub class and see the nature of the print statements.
class subClass extends superClass
{
static
{
System.out.println("sub class initialized");
}
}
public class Test
{
public static void main(String[] args)
{
System.out.println("Accessing static i:" + subClass.i);
}
}
Notice how in the main method I am accessing the static variable "i" via the sub class and not the super class (to which it actually belongs). This code when executed produces the following lines
Super class initialized
Accessing static i:10
See how this test code will not initialize the child although the variable is invoked through its namespace.
So much for the digression, and let me return to the main topic of the article, namely the side effects of static initialization. Static access happens when you access a static variable or invoke a static method, or instantiate one of its type. This will automatically trigger a whole lot of things. First off the class they are part of is initialized if it is not already initialized. This implies all of the static fields will be initialized. If this initialization involves any newing of classes, then a whole lot of constructors are called. This is followed by the execution of numerous static blocks that are there for that class. In fact the side effects are further compounded when the class in case is inheriting other classes as those classes get initialized first.
Consider the following static class with three static functions "sf1", "sf2", and "sf3".
public class sc
{
public static void sf1(){ .... }
public static void sf2()
{
SomeResource r = new SomeResource();
r.primeTheResource();
doSomething(r,"otherstuff");
}
public static void sf3(){ .... }
}
Off the three functions, I have provided body for one of the functions "sf2". This function acquires a resource, and primes the resource before doing something with it. If the resource "r" is not changing after priming it, it is possible to optimizing the code once and using it again and again. Static initialization immediately suggests itself as a possible solution. That intuition leads to the following code
public class sc
{
private static SomeResource r = null;
static
{
SomeResource r = new SomeResource();
r.primeTheResource();
}
public static void sf1();
public static void sf2()
{ doSomething(r, "otherstuff");
public static void sf3();
}
See how a static block is used to initialize the resource "r". Because of the static block this initialization takes place only once. That leaves the function "sf2" to just use the resource instead of initializing it every time. So far so good. When I have started using static initialization to solve one such problem, my work would have stopped here. But there are some issues with this code on further examination.
Suppose there is a rule that primeTheResource()
cannot be called unless the system is initialized. This means there is a point in the application initialization process before which r.primeTheResource()
is invalid. While writing this class I am quite confident that "sf2()" is always called after the application initialization. But the static class "sc" is designed to be a utility class. So the application initialization process sees that there is a very useful function called "sf1" and decides to use it as part of the application initialization process.
Guess what now. Calling "sf1" as part of initialization has invoked r.primeTheResource()
which expects the initialization to be complete before being valid. Such unwanted dependency took place because I broke the class cohesion rule which states that a class is not a general collection of methods but a cohesive related module. The cohesion rule is apt and usually correct when I am designing instance classes. But the class "sc" being a utility class, it is a pain to design 'n' utility classes for 'n' purposes.
The unwanted dependency demonstrated so far can be broken by using a holder class for that can hold the single resource "r". Here is an example
public class sc
{
public static void sf1();
public static void sf2()
{ doSomething(ResourceHolder.r, "otherstuff");
public static void sf3();
}
See how the static class no longer holds a reference to the static variable "r", instead borrows it from its holder class. Here is the ResourceHolder class that hosts the static variable "r" and initializes it at its first use
public class ResourceHolder
{
public static SomeResource r = null;
static
{
SomeResource r = new SomeResource();
r.primeTheResource();
}
}
So far I have talked about abstract examples to show dependencies and the Static Resource Holder pattern. I would like to show now a concrete example of how the Resource Holder pattern could be used. In this example I want to take a parameterized url string and then replace the parameters with their actual values to get the final url. The parameterized url would look something like this
/{aspireContext}/display/url=ShowPage1URL&arg1={arg1}&arg2={arg2.encode}
If aspireContext is "akc" and arg1 is "15" and arg2 is "abc xyz" then the expanded string will look like
/akc/display/url=ShowPage1URL&arg1=15&arg2=abc+xyz
Now let me consider the static method that does the substitution
public static String getSubstitutedURL(String urlString,
Map urlArgs)
{
Map map = new HashMap();
//Shell dictionary
IDictionary paramDictionary = new MapDictionary(map);
//Search context dictionary first
paramDictionary.addChild(ContextDictionaryHolder.s_contextDictionary);
//Search url arguments next
paramDictionary.addChild(new MapDictionary(urlArgs));
//Search application configuration last
paramDictionary.addChild(ConfigDictionary.self);
//Replace heeding the rules of url encoding
return SubstitutorUtils.urlencodeSubstitute(urlString,paramDictionary);
}
The method uses hierarchical dictionaries to resolve parameter names to their values. Importantly for this discussion it uses a cached dictionary called "context dictionary" which is always the same for a given web context. Instead of maintaining a static variable for the context map that needs to be prepared once for the application inside the class, the solution uses a "ContextDictionaryHolder" class to do the acquiring and initializing. The code for the ContextDictionaryHolder is as follows:
class ContextDictionaryHolder
{
public static IDictionary s_contextDictionary = null;
static
{
String aspireContext = ServletUtils.getWebApplicationContext();
if (aspireContext == null) aspireContext = "";
HashMap m = new HashMap();
m.put("aspirecontext",aspireContext);
//Place other context related information into this dictionary
.....
//Finally hold that in a dictionary
s_contextDictionary = new MapDictionary(m);
}//end of function
}//end of class
See how the static variable s_contextDictionary is initialized using a static block and how the side effects are localized to only this class. Depending on the release of the servlet api and the servlet container there could be better ways of solving the context problem. Nevertheless this code demonstrates how static resource holders could be used in real situations.
Based on the discussion, a java class with static blocks and a lot of static functions should flag a warning as invocation of these functions may wrongly trigger side effects. This means one has to pay special attention to side effects similar to this when one is writing static blocks. I don't think I will strongly advocate to convert all static blocks to static resource holders but one has to see if a given situation necessitate a static resource holder. When you do see unwanted side effects you can use Static Resource Holders to eliminated those unwanted side effects.
1. Class initialization process from the Java Language Specification, 2nd edition
2. Static initializer syntax regulations from the Java Language Specification, 2nd edition
3. C# Static constructors demystified at O'Reilly's ONDotnet.com