raganwald
Wednesday, April 25, 2007
  Rails-style creators in Java, or, how I learned to stop worrying and love anonymous inner classes
Let’s begin with a well-known problem: creating a Map that is to be pre-populated with a few values. Here is some naïve code that creates a Map and then puts two values into it:


final Map<String, Object> mm = new HashMap<String, Object>();
mm.put("foo", "Strive To Finish Up");
mm.put("bar", "Public House");


Although this works, the problem with the naïve code is that it does not say with conviction that the two put calls are part of the creation of the Map. If you move code around, it’s easy to drop a line. This code is literal, but it is not literate.

Most Java programmers1 are familiar with the Map Initializer Idiom:


final Map<String, Object> m = new HashMap<String, Object>() {{
put("bar", "saloon");
put("bash", 7);
}};


This creates a new Map and populates it with two members. This is a big improvement. The initialization is clearly embedded in the line of code that creates the Map. Thanks to a small syntax hack, it is (by Java standards) concise.

If you’re into the details, it actually creates a new anonymous inner class that extends HashMap. The inner class doesn’t add any new instance members, but it does contain an initializer: code between braces is run when instances are initialized. That’s why there are double braces: the outer set delineates the body of the anonymous inner class, the inner set delineates the initializer block.

Note that your new Map isn’t exactly equal to any HashMap, because it has a different class. That sometimes matters.

POJOs

Many Java programmers labour with applications where the original architect wielded the Golden POJO Hammer: absolutely everything in the application looked like a POJO nail. I work with one such code base: it is obviously a traditional Procedural application. Getting anything done involves calling a global procedure and passing in a bunch of arguments.

The original architects worked for one of those Global Services companies, and you can’t charge hundreds of dollars an hour2 writing programs that our grandparents would recognize from the sixties. So to add a layer of OO, they turned every procedure call into a method, so a simple call like:


final BigDecimal balance = AccountModule.getAccountBalance("12345-678");


became:


final BalanceDoer doer = new BalanceDoer();
doer.setAccountNumber("12345-678");
doer.doit();
final BigDecimal balance = doer.getBalance();


(The nice thing about using this “OO Style” is that you get named parameters and multiple return values. I shall leave it to the static type checking enthusiasts to point out the drawbacks of this approach.)

Well, we can use the same initializer idiom with POJOs like BalanceDoer (although you may have to move doit() outside of the initializer if you need checked exceptions):


final BalanceDoer doer = new BalanceDoer() {{
setAccountNumber("12345-678");
doit();
}};
final BigDecimal balance = doer.getBalance();







A Little Java, a Few Patterns is brought to you by the authors of The Little Schemer, a book that teaches recursion and first-class functions: it is no surprise to discover that their book about Java eschews the same old, same old Hello World approach in favour of teaching deep ideas about Object-Oriented design and Pattern-Oriented design using Java as the language of instruction.
Again, you get a more literate snippet of code: the initialization and invocation all belong together, and you have put them together. If you move this around, you won’t drop an important line by mistake. And you get to save some keystrokes if there are a lot of fields to initialize.

If you dare to use protected fields in POJOs (this is heresy to the “lock everything down so that other programmers subclassing your stuff can’t actually change anything” zealots), you can even write accountNumber = "12345-678"; in the initializer instead of using a setter.

I prefer that form, it looks a lot more like what you are trying to say: this field has this value for this doit call. That may be a matter of taste, or I may be overlooking something important.

Remember, your new object is an instance of an anonymous inner class, not of the original POJO class. This matters greatly if you test for class membership with equals instead of substitutability with instanceof.

What does this have to do with Rails?

This is where we could go off on a long essay about how using things like Lisp, Smalltalk, and Ruby on Rails opens your mind to possibilities. That when you get used to MyModel.create(:foo => 'Shove That Fish Under'), you look for ways to make your Java code easier, and so forth.

But honestly, you knew that already, didn’t you?

Update: Writing programs for people to read.


  1. Where by “most,” I mean those who haven’t been hiding under the “Java-programs-must-only-contain-approved®-design-patterns: all-other-idioms-are-considered-hard-to-read-by-mediocre-colleagues” rock.

    In my experience, that is the majority of good programmers. If reading blogs convinces you otherwise, remember that many of the best people are too busy building good stuff to write about building good stuff.

    Update: A commenter expressed some surprise that this is a well-known idiom. Have a look at Double Brace Initialization.

    The other Java people, the ones with time on their hands, or the ones that consider themselves “too good to program,” are the ones that write posts explaining why Java programs must be dumbed down to the lowest common denominator. I also blog. Draw your own conclusions from the evidence.

  2. Not this company, although that’s an amusing post.

Labels:

 

Comments on “Rails-style creators in Java, or, how I learned to stop worrying and love anonymous inner classes:
I imagine I should feel embarrassed that as a Java programmer (and one whose knowledge of other languages is not non-existent, but less solid than it could be) the 'Map Initializer Idiom' is not one that I'm really familiar with. But it's one that I would have thought couldn't be relied upon. Obviously it works, at least on your machine (I presume), and on mine (having tested it). But it seems as though the Java Language Spec says it should: the instance initializer block should be executed prior to the constructor, according to s12.5 of the spec, and yet apparently (according to Eclipse's presentation of its source code) java.util.HashMap doesn't initialise its underlying data store (the 'table' field) until the end of the constructor. Anyone have any ideas on what I'm getting wrong here?
 
Sam:

You are correct that initializers are called before constructors in a class, but remember that the superclass is constructed before the class being instantiated.

So in the case of our Map Initializer Idiom, if the class HashMap had an initializer, it absolutely would be called before its constructor.

However, HashMap does not have an initializer. Our anonymous class has an initializer. So first the HashMap is fully constructed, and then our initializer gets called.

This makes it safe to use for Maps and POJOs. Or at least, safe in this respect. Problems with class equality must still be respected.

If this does not seem clear, please comment or email. I can post a simple test file showing the order.
 
Hmm. Oops. Should have continued reading the spec at least until the next page, where they give an example that proves my understanding wrong! Also perhaps should have thought longer and harder about my question...

Perhaps you'll accept my lame excuse that I've been worrying lately about initializers/constructors calling non-final methods for fear of unanticipated problems from subclasses overriding them in unexpected ways (maybe I've been treating problems reported by FindBugs too religiously!).

Thanks in any case for your clear and simple response. And, of course, for your excellent blog.
 
It doesn't work for HashMap and the like, as their code is not under your control, but my preferred idiom for doing this sort of thing is method chaining. Where you have a method like put or setFoo, rather than have it return void it should instead return 'this'.

So we could (theoretically) replace

MyMap map = new HashMap(){{ put("foo", "bar"); }}

MyMap map = new HashMap().put("foo", "bar");

This works particularly well with builder classes. One of my toy projects generates a lot of code that looks like

Foo foo = new FooBuilder().setBar(bar).setBaz(baz).build();

Where Foo is an immutable class.

I've even figured out a way (indeed, two ways) to make this entirely type safe, but it's horrific and overuse will make the VM cry bitter tears at you, so I've decided against implementing it. :-)
 
my preferred idiom for doing this sort of thing is method chaining.

Ah yes, this is the kind of thinking you do when you've been exposed to SmallTalk: Smalltalk has this built into the language automatically.

I've even figured out a way (indeed, two ways) to make this entirely type safe, but it's horrific and overuse will make the VM cry bitter tears at you, so I've decided against implementing it.

Would "Currying" be one of the two ways?
 
Something to think about: If for some reason an exception is thrown inside the initializer code, the compiler will tell you that the error is on the line of the declaration, not the actual method call.
 
If for some reason an exception is thrown inside the initializer code, the compiler will tell you that the error is on the line of the declaration, not the actual method call.

Very good point. I personally haven't used this idiom anywhere where I anticipate an exception, but in Java... you never know when a NullPointerException or some such will bite you.

Thanks for the tip!

Also, I didn't mention it before, but all variables from the enclosing scope must be declared final if they are used in an inner class like this.

That goes for parameters to an enclosing method as well as for local variables.
 
Why not just create a method createMyMapAndMakeSureItsPrepopulated that returns your Map created with the objects you wanted put in it?

Apparently there are a lot more than just mediocre programmers hiding under that rock. Google replies with 'Your search - "Map Initializer Idiom" - did not match any documents.'

Is the goal to englighten or seem englightened? Good luck.
 
I've actually never been exposed to Smalltalk. It's on my list of languages I really should learn at some point, but this list is large and my time is finite. :-) I came up with this one independently.

Currying is definitely a good way to make this type safe, but I wanted it to have the property that you could commute the order in which you applied the set methods on the builder object - i.e. you can apply them in any order, but they must each be applied exactly once.

The two solutions respectively involve 2^n interfaces and a type signature that grows as n! (where n is the number of parameters). You can probably see why I decided against it. :-)
 
Currying is definitely a good way to make this type safe, but I wanted it to have the property that you could commute the order in which you applied the set methods on the builder object - i.e. you can apply them in any order, but they must each be applied exactly once.

I strongly suspect that what you're doing is currying, just that you have to "roll your own," since your language won't do it for you.

That being said, there is an awful lot of cleverness required to make it reasonably elegant. I considered adding a feature like this to Java for the horribly over-POJO'd application I describe above.

I couldn't think of a way to do it without code generation, so I dropped it.
 
Why not just create a method createMyMapAndMakeSureItsPrepopulated that returns your Map created with the objects you wanted put in it?

Aaah, a very good question. I presume you mean, why not refactor the code into a private helper method, since it's only used in one place.

This encapsulates the elements in the map, so when you're looking at the code later you have to jump to the helper method to understand what it does.

Sometimes, that's what you want: the exact elements are not important to understanding the rest of the code, so "hiding them" behind the abstraction of a method is a good thing.

Sometimes you want to communicate what is being put in the map, and this approach is better. It is similar to using a let is Scheme.

Apparently there are a lot more than just mediocre programmers hiding under that rock. Google replies with 'Your search - "Map Initializer Idiom" - did not match any documents.'

I may have been creative with the name. But you don't need to look very hard to find examples of the idiom: Double Brace Initialization.

Is the goal to enlighten or seem englightened(sic)? Good luck.

What do you care?
 
This post has been removed by the author.
 
What if I use a helper but with something like:
Object[][] mapValues={{"keyA",valueA},{"keyB",valueB},{"keyC",valueC}};
Map map=CollectionsCreator.getMap(mapValues);

I'm being "java-verbose" and sure you don't mind throwing type safety away ;-), but it seems the intent of the map is clear and is more closer to other languages...
Also is two steps and needs a helper, but I like how the map reads "{key, value},{key, value},..."
(anyway, I'm just exploring the idea :-))
 
Off topic, sorry, but I followed the link for "A Little Java, ..." because I loved The Little Schemer so much. One of the reviewers there complained that the book uses inheritance for composition of functionality. If this is true, it shouldn't be recommended (this reveals a deep misunderstanding of OO), and many readers will look at a link from your site as a recommendation.

I'm just saying.
 
Yes, links to books from my sites are recommendations.

As it happens, I think the question of how to compose functionality and where to use inheritance are huge topics, far too huge to be condensed into a simple rule.

For one thing, when writing Java you are working with a hobbled language. You do not have multiple inheritance. You do not have WAS-A (protected or private inheritance). You do not have true delegation. Any choice you make is necessarily a compromise based on pragmatism, not an expression of how programs ought to be written.

I like the book and am happy to recommend it. Your objection has been noted.
 
There is one slight drawback to using this technique. For an explanation see the FindBugs description of SIC: Could be refactored into a named static inner class. In most cases that won't be a major concern, but it's a factor that has to be considered in the design trade-offs.
 
Nick:

You are very correct. It's something I had noted in the app I mentioned, but it wasn't much of a problem because the objects were short-lived.

Refactoring it into a named static inner class would totally destroy the utility of the idiom, of course, but it is something to think about.
 




<< Home
Reg Braithwaite


Recent Writing
Homoiconic Technical Writing / raganwald.posterous.com

Books
What I‘ve Learned From Failure / Kestrels, Quirky Birds, and Hopeless Egocentricity

Share
rewrite_rails / andand / unfold.rb / string_to_proc.rb / dsl_and_let.rb / comprehension.rb / lazy_lists.rb

Beauty
IS-STRICTLY-EQUIVALENT-TO-A / Spaghetti-Western Coding / Golf is a good program spoiled / Programming conventions as signals / Not all functions should be object methods

The Not So Big Software Design / Writing programs for people to read / Why Why Functional Programming Matters Matters / But Y would I want to do a thing like this?

Work
The single most important thing you must do to improve your programming career / The Naïve Approach to Hiring People / No Disrespect / Take control of your interview / Three tips for getting a job through a recruiter / My favourite interview question

Management
Exception Handling in Software Development / What if powerful languages and idioms only work for small teams? / Bricks / Which theory fits the evidence? / Still failing, still learning / What I’ve learned from failure

Notation
The unary ampersand in Ruby / (1..100).inject(&:+) / The challenge of teaching yourself a programming language / The significance of the meta-circular interpreter / Block-Structured Javascript / Haskell, Ruby and Infinity / Closures and Higher-Order Functions

Opinion
Why Apple is more expensive than Amazon / Why we are the biggest obstacles to our own growth / Is software the documentation of business process mistakes? / We have lost control of the apparatus / What I’ve Learned From Sales I, II, III

Whimsey
The Narcissism of Small Code Differences / Billy Martin’s Technique for Managing his Manager / Three stories about The Tao / Programming Language Stories / Why You Need a Degree to Work For BigCo

History
06/04 / 07/04 / 08/04 / 09/04 / 10/04 / 11/04 / 12/04 / 01/05 / 02/05 / 03/05 / 04/05 / 06/05 / 07/05 / 08/05 / 09/05 / 10/05 / 11/05 / 01/06 / 02/06 / 03/06 / 04/06 / 05/06 / 06/06 / 07/06 / 08/06 / 09/06 / 10/06 / 11/06 / 12/06 / 01/07 / 02/07 / 03/07 / 04/07 / 05/07 / 06/07 / 07/07 / 08/07 / 09/07 / 10/07 / 11/07 / 12/07 / 01/08 / 02/08 / 03/08 / 04/08 / 05/08 / 06/08 / 07/08 /