Thursday, August 16, 2007

Instantiate and initialize a HashMap in one statement

There must've been quite a few occasions when you found yourself writing an Interface for your project that stored all the Constants - a centralized place for all the names and values.

In my case, I've had to store not just a bunch of names, but associate some additional descriptions with the names as well. So, how do you do it if you are using an Interface to store these Constants and at the same time initialize them?

Well.. there's a way of creating a HashMap and initializing it with values in a single Statement. All it needs is an Anonymous Inner Class that extends the HashMap and an unnamed code block between Curly Braces. Don't mistake this for the Static code block that we use to load JDBC Drivers. This unnamed block is executed after the instance is created (i.e after the HashMap's Constructor is invoked)

This is how you do it:
[Updated Apr 12, 2012]

public interface ProjectConstants {
    /* Remember, all constants in an interface 
       are "public static final" so you don't have 
       to declare it. */

    Map<String, String> NAMES = 
            Collections.unmodifiableMap(
                    /* This is really an anonymous 
                       inner class - a sub-class of j.u.HashMap */ 
                    new HashMap<String, String>() {
                        {
                            //Unnamed init block.
                            put("homer", "simpson");
                            put("mickey", "mouse");
                            put("eric", "cartman");
                        }

                    });

    .. .. .. .. more constants .. 

    int HIGHEST_ALLOWED_VALUE = 37;
}

6 comments:

Geoffrey Wiseman said...

Unnamed block == instance initializer

Unknown said...

Fields in interface == public, static, and final

Ashwin Jayaprakash said...

Well, the access-modifiers are unnecessary, but it's still alright. Force of habit.

Stanimir Simeonoff said...

You would be better off w/ a package private or inner class (inner class is easier to type but becomes a small part in the interface) that has methods and does the same initialization.
Just a note unmodifiableMap for an interface instance is also a good tip.
The idiom below can initialize more sophisticated structures and even read from the disk (e.g. some localization data, etc)


public interface A {
Map<String, String> m= X.newMap();
static class X{
private X(){
}
private static Map<String, String> newMap(){
Map<String, String> m = new java.util.HashMap();
m.put("1", "2");
m.put("a", "b");

return Collections.unmodifiableMap(m);
}
}
}

Паша Мусієнко said...

Thanks, useful tip!

Carlos G. González said...

Thx. It's very useful.