Haravikk
Haravikk

Reputation: 3280

Best Method to Initialise Complex Static Values

I have a class that may need a large, but unchanging, data-structure based on the contents of an enum class.

What I'm interested to know is whether it is better for me to initialise this in a static block, or should I only initialise it within the method that actually accesses the data (in case it's never actually used)?

Here's an example:

public enum MyEnum {
    FOO ("foo"),
    BAR ("bar"),
    FOOBAR ("foo_bar");

    private final String otherName;

    private MyEnum (String otherName) {
        this.otherName = otherName;
    }

    private static final Map<String, MyEnum> otherNames = new HashMap<String, MyEnum>();
}

Now, I have two options for initialising the otherNames map, first being to use a static block like so:

static {
    for (MyEnum entry : MyEnum.values()) 
        otherNames.put(entry.otherName, entry);
}
public static MyEnum valueByOtherName (String otherName) {
    return otherNamesStatic.get(otherName);
}

Or alternatively I can initialise the map the first time a lookup is actually requested like-so:

public static MyEnum valueByOtherName(String otherName) {
    if (otherNames.isEmpty()) { // Or test against null or whatever
        for (MyEnum entry : MyEnum.values())
            otherNames.put(entry.otherName, entry);
    }
    otherNames.get(otherName);
}

In particular I'm interested to know whether Java will optimise the static block such that it can pre-generate the map on future runs (since it's based on the enum so if it hasn't changed, then neither has the map) or will it run the static code every time the class loads, in which case only doing it when needed may be more efficient?

Upvotes: 1

Views: 62

Answers (2)

Serge Ballesta
Serge Ballesta

Reputation: 148910

As long as I understand Java, the ClassLoader calls the static initialization block at the moment it loads the class and only at that moment. So :

  • if using a static block, you are sure it is called at least once if you use class MyEnum even if you do not use valueByOtherName and it will never be called again until the jvm is closed (unless you have independant ClassLoaders loading same class which should be at least strange). But you have no extra test in valueByOtherName
  • if using initialization on first lookup, the block will be called only if you call valueByOtherName and by construction will never be called again. But you have an extra test in each call to valueByOtherName

IMHO it is far better to use a static block. And it is far more readable ...

Upvotes: 2

Tasos P.
Tasos P.

Reputation: 4114

Static blocks are executed every time the class is loaded (not every time an object is instantiated). So, unless your environment uses several class loaders, your static initialization block will run only once.

Having that said, I'd suggest to use the static block which is cleaner (IMHO).

Also check this answer for your reference.

Upvotes: 3

Related Questions