Java is an OO language. Much of the functionality of an 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 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);
.. so on and so forth
}
I have a similar class for FileUtils
public class FileUtils
{
static public void
runFileProcessorWith(String filename,
IFileProcessorListener callBackProcessor);
throws IOException;
static public String
translateRelativeFilename(String filename);
static public String
copy(String fromFile, String toFile)
throws IOException;
static public String
getBaseName(String filename);
static public String
getAbsolutePath(String filename);
.. so on and so forth
}
One characteristic of static functions is that they are stateless. But for efficiency they may depend on some static variables. When this happens you need to know the class initialization rules laid out by the language. Although these rules are fairly intuitive rules it is beneficial to know them in some depth, as static initialization result in side affects.
This article is about minimizing these side affects.
With that in mind let me review the basics of static initialization rules. For a compplete treatment of the rules refer to the java language specification links at the end of the article.
Simplified rules of static initialization
- A class is initialized before any of its members are accessed. This includes class variables and static functions.
- Before a class is initialized its superclass is initialzed first
- You can use static blocks to initialize static variables
- Static variables and static blocks are executed in the order they appear in source code(so called textual order)
- A class is initialized before any of its instances can exist
Rules of static blocks
- Cannot return
- Can throw runtime exceptions
- Cannot throw checked exceptions
- Cannot call this or super
Static initialization surprise
public class super
{
public static int i=10;
static
{
System.out.println("Super called");
}
}
public class child extends super
{
static { System.out.println("Child initialized");}
}
public class test
{
public f1()
{
int j = child.i;
}
}
This test code will not initialize the child although the variable is invoked through its namespace, because the variable belonged to the super class. So you will only see "Super called" printed and not "Child initialized".
The shock affect of static access
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 affects are further compounded when the class in case is inheriting other classes as those classes get initialized first.
Back to the utility class again
As stated earlier a class with a set of related static methods can be called a utility class. Let me consider another example this time.
public class sc
{
public static void sf1();
public static void sf2();
public static void sf3();
}
This class defines three static methods.
Optimizing the static function: sf2()
Assume that sf2() is called all the time and requires optimization
public static void sf2()
{
SomeResource r = new SomeResource();
r.primeTheResource();
doSomething(r,"otherstuff");
}
If "r" is not changing I would like to cache it and use a static block to initialize it
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();
}
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. The author of "sf2()" is 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 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.
This happened because I broke the class cohesion rule where it says that a class is not a general collection of methods but a cohesive related module. This is usually correct when I am designing instance classes. But this being a utility class, it is a pain to design 'n' utility classes for 'n' purposes.
Solution: Static Resource Holder Pattern
This can be solved by using a holder class for that one resource and get the dependency out of the utility class "sc". 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 variale "r" and initializes it at its first use
public class ResourceHolder
{
public static SomeResource r = null;
static
{
SomeResource r = new SomeResource();
r.primeTheResource();
}
}
Actual example from Aspire
So far I have talked about abstract examples to show the Resource Holder pattern. Let me now give a concrete example taken from the source of Aspire a declarative RAD tool for J2EE and XML. The following method is responsible for embedding a "urlString" with proper parameters so that the expanded string will have the user parameters susbstituted. As an example consider the following parameterized urlString:
/{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 this
public static String getSubstitutedURL(String urlString,
Map args)
{
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(args));
//Search configuration last
paramDictionary.addChild(ConfigDictionary.self);
//Replace
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 inside the class it uses a "ContextDictionaryHolder" class to do that. The code for this class 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);
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 affects are localized to only this class.
References
1. Class initialization process from the Java Language Specification, 2nd edition
2. Static initializer syntax regulations from the Java Language Specification, 2nd edition
3. Static constructors demystified at O'Reilly's ONDotnet.com