Home > Uncategorized > Watch out when using “static final String” declarations in Java

Watch out when using “static final String” declarations in Java

I was cleaning up my print-outs from the past (2000- era) the other day, when I came across an interesting e-mail discussion I was having with a colleague on Java resource bundles and string constants. At that time I was still working on the E-Slate platform (an "IDE" enabling educators and students to author educational microworlds by plugging components together [sort of "wiring"] and/or scripting them using Logo/JavaScript) and one thing I loved was those e-mail discussions (we had been a distributed team for some years already, thanks to the loosely coupled component-based approach adopted in E-Slate’s architecture).

The guy warned the rest of us to be careful when renaming a property in a ResourceBundle (a key-value container especially useful for the internationalization [or could say dynamic/on-the-fly localization] of a project, pioneered by a company IBM had acquired by that time). He had been struggling to find out why he was getting "null" for a property some times only to realize that at some of his classes’ source code he was referring to that same property as "iconBase" and at others as "baseIcon". Obviously he expected ResourceBundle to throw an exception if you ask for a missing property, but it is returning null by design.

A solution he could have used in other language could be to override the method that gets a property by name to throw an exception, but since in Java you have to declare exceptions thrown that would not only break the conceptual design of the ResourceBundle, but not even be allowed by the Java compiler. Another trick he could pull was to add a separate method of his own for the lookup that would use "throw exception if property not found" semantics (instead of the C-like "return null if not found" design).

Because of such issues it’s a bad idea to have literals (string tokens) hard-coded in your source code and should better use constants for property names:

public static final String ICON_BASE_PROPERTY = "iconBase";

However one should be extra careful when using such constants from other classes that talk to the class that defines those public constants (e.g. using the constants at PropertyChangeListener classes that monitor the property changes of a class instance that defines those constants). That is because the Java compiler copies the string constants to the class that uses them instead of using some kind of reference to the original class that defined the constants. So if the constant text is edited at the original class (say change ICON_BASE_PROPERTY to "myIconBase" from "iconBase") and the classes that are using the ICON_BASE_PROPERTY constant aren’t recompiled, then those other classes will keep on using the old string literal value (iconBase) so parts of the application code at runtime will be using the new value and other parts the old one, a potentially disastrous and hard to identify bug. This can easily be the case if component based development is employed, with each component being developed separately and shipped as a compiled JAR file for the main application to load dynamically, as was the case in E-Slate development.

The reasoning for this Java compiler behaviour is probably the use of the "final" modifier in the definition of the string literal. But "final" should mean you’re not allowed to override/change that value at a descendent class, not that you should never edit that string constant in your source code again.

A workaround could be to use interfaces, define all constants in the interface and have both yours and other classes that want to use the constants inherit from that interface. That way the Java compiler wouldn’t copy string literals to those classes (I hope!) and as long as that interface shipped only inside one JAR (the one shipped by the person who maintained it) and other classes would use the interface from that JAR all would be fine, even if the classes inheriting from that interface were compiler with earlier version of it (as long as the method signatures of that interface didn’t change, but only some constants in it changed value). This is just a theory though, better try it first before applying it into production :-).

Categories: Uncategorized Tags:
  1. DC
    2012/03/02 at 03:33

    This was all god information, until that last few sentences!

    Never use an interface to define constants. Why?
    Just google things like:

    java constants interface
    java methodless interface

    You’ll get a plethora of reason why it’s a bad practice.

    • 2012/03/03 at 13:00

      Just googled on those suggested terms and if you read comments at those posts you’ll see many people don’t agree. I believe I explained in that post the problem with constants that get copied around when you using classes, breaking code when changed and clients haven’t been recompiled again. Not working that is for public APIs used by sw components that are pluggable binaries into an app. Don’t want to recompile them each time the app changes if the app respects API contracts using versioned interfaces.
      In fact the reason for an interface to carry constants as is done in Sun’s own platform code is that those constants are parts of some protocol. Allowed parameters of some API can’t be expected to be in some javadoc and entered by API consumers with typos the compiler won’t catch, leading to runtime errors. Adding them to immutable versioned interfaces is the correct and most portable way in my opinion.

  1. No trackbacks yet.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.