Little Known Secrets of Java: Better Constants

Sometimes, every once in a while, I come across something in the dark recesses of Java that surprises me. Most recently I was reading through the code for Netflix's Curator library and I came across a little gem so interesting, so tantalizing, that I had to read the JDK's javadocs just to be sure it was right.

So what is this little secret? Ladies and Gentleman, let's talk about constants.

What's in a Constant?

First, let's clarify what I mean by a constant. Let's say that we have some useful value we wish to define. Furthermore, let's say this value is something I intend not to change during the execution of my program. You might even go so far as to say it is constant.

Our First Try

A first attempt to define such a value might look something like this:

public class Foo {
 
 
     // set the session timeout to 1 hour (in ms)
     public static final int SESSION_TIMEOUT = 60*60*1000;
 
 
     // other methods elided // 
 
}

Wonderful. Welcome to junior programmer land. You can pick up your ID badge with Jane in HR.

A Better Idea

While the above is quick and dirty and gets the job done, alas, Dijkstra would not like it.

dijkstra.jpg

Perhaps we can improve on this. First, let's examine: is that constant really a constant?

Is that Constant REALLY a Constant?

It's pretty presumptuous of us to assume we know what is constant, isn't it? Like, it's a tad cheeky. See, when I think of a constant I think of, say: π. These are things that, given the task of manipualting them, we can safely code them into our programs–hard code even–and never think twice about it.

But alas, what about our session timeout? If you consider the true purpose of session timeout, you will find that it is really something that is subject to change, based on some arbitrary business rules. In fact, session timeout is really a variable; a variable that doesn't change at runtime.

Defining Integer Constants

So how to do this in Java? XML files? Databases? Property files? Close, but then we have to build all that code to read the properties, serialize them back out to files… Not ideal. What about our old friend System.getProperty()? Close, but then we have to do String conversion anywhere we want to use it. Things brings us to…

The Secret

The Java implementation of Integer offers an often overlooked method: getInteger(). Here's how you use it, by way of an example, taken from Netflix Curator:

 
public class CuratorFrameworkFactory
{
    private static final int        DEFAULT_SESSION_TIMEOUT_MS = Integer.getInteger("curator-default-session-timeout", 60 * 1000);
    private static final int        DEFAULT_CONNECTION_TIMEOUT_MS = Integer.getInteger("curator-default-connection-timeout", 15 * 1000);
 
    private static final byte[]     LOCAL_ADDRESS = getLocalAddress();
 
    private static final CompressionProvider        DEFAULT_COMPRESSION_PROVIDER = new GzipCompressionProvider();
    private static final DefaultZookeeperFactory    DEFAULT_ZOOKEEPER_FACTORY = new DefaultZookeeperFactory();
    private static final DefaultACLProvider         DEFAULT_ACL_PROVIDER = new DefaultACLProvider();
    private static final long                       DEFAULT_INACTIVE_THRESHOLD_MS = (int)TimeUnit.MINUTES.toMillis(3);
 
// other methods elided //
 
}

Essentially, what the getInteger() method does is allow you to access a value in the system properties, but without littering your code with the String to Integer conversion. What's better is you can name these values and even specify default arguments. Very nice indeed. Oh, and for those of you who don't know how to set these properties, you can do it a number of ways, but most easily on the command line when invoking your Java program.

Example: java -Dmyproperty=myvalue MyClass

You can learn more by looking at the documentation for System.getProperty().

Wrapping Up

So there you have it. One little function in the Integer class that may just end up making your code just a little bit more awesome.

And, because I feel like I have to say it: Please don't write me about using enums. Trust me, I know they exist. I just think that for this application the getInteger() approach is much better.