Thursday, August 30, 2007

Java Initializers - Add elements to a collection type at construction time

I have always had envy on languages that allows you to do this kind of declarations:
var mapLikeType = { "key1" => "value1", "key2" => "value2" }
A variable is declared, initialized to a new Map type instance, and initial values are loaded into the type. Ruby and Perl can do this, hey, even C# can do this in its v3 instance.

Well, Java can too. Sort of.
Map mapLikeType = new HashMap() {{ put("key1", "value1"); put("key2", "value2"); }};
So what is going on here?
  • A variable mapLikeType is declared of type Map
  • An anonymous class, inheriting HashMap, is created
  • The static initializer inside is executed, which puts values into the instance
  • The variable is initialized to the instance of the class
Formatting the code a little different makes it more obvious.
Map mapLikeType = new HashMap() {
{
put("key1", "value1");
put("key2", "value2");
}
};
I am not sure I would use it in production code. It seems like a serious vaste of resources to generate a new anonymous class at each instantiation.

But, I do use it in test code. Often, when writing unit tests, I need to setup part of the domain model with some initial values. The same trick can be utilized there. Assume we have a domain model of Book and Author classes. Here is how to setup a collection type with some data in it:
    Set books = new HashSet() {{
add(new Book() {{
setTitle("The Art of Computer Programming");
addAuthor(new Author() {{ setName("Donald E. Knuth."); }});
}});
add(new Book() {{
setTitle("A Method of Programming");
addAuthor(new Author() {{ setName("Edsger Dijkstra"); }});
}});
}};
This only works on non-final classes.

5 comments:

Iwan Memruk said...

never seen this before :)
witty

A.A.A said...

This sort of initialization code only handy in Tests, it is almost never required to use such initialization in real business logic.

Open source reader said...

pretty smart !
Delicous'ed :)

Anonymous said...

"This sort of initialization code only handy in Tests"

Wow. You really can't think of a use for this in production code?

I've got lots of production code where I was initializing Maps and Lists in static blocks. It is very handy for specifying "handler" interface implementations for types and values. This technique will make that code much more compact.

And that's just off the top of my head.

Sean Reilly said...

FYI: It's an instance initializer, not a static one. If it was a static initializer then the inner set of braces would be after the static keyword, and you wouldn't be able to call instance methods in it.