Nat Pryce introduced me to a bit of Java syntax that is simple, useful and suprisingly little used or known.
It was a suprise to find this syntax after so long - I've been writing Java on-and-off for 10 years - it isn't new syntax and I've pair-programmed with people who have written more Java than me who didn't use this syntax - I don't know why it isn't used much more frequently.
Consider this code:
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
using the syntax that Nat showed me, can be written as:
ArrayList<String> list = new ArrayList<String>(){{
add("hello");
add("world");
}};
which is neater, particularly if it's a field declaration with assignment.
The language which I think has the neatest syntax of any I've used commercially is Smalltalk - it's lovely. In Smalltalk, there is a syntactic construct called "cascading messages" which is similar but more general. The Java syntax above calls the "add" methods on the newly created ArrayList. You can't send multiple messages to the same receiver in the general case, just on construction. For example:
ArrayList<String> list = new ArrayList<String>();
list{{
add("hello");
add("world");
}};
is not legal.
In lots of cases, I avoid using language features or syntax that is unusual. However, in this case, I think this syntax is easy to understand and deserves to be more commonly used.
Sponsor me for the National Autistic Society's London to Paris Bike Ride. OK - so it's not relevant to the article, but they've been very good to me and my autistic son, and my fundraising could do with a boost.
Posted by ivan at December 28, 2006 5:18 PMI like that syntax. I can't remember when I first saw it, a year or so ago I think. I started using it a lot, particularly to create collections with a few items prepopulated. I too have rarely met anyone else who knew or used it.
A word of caution though. I think technically this is an anonymous inner class with an instance initialiser. When you compile your code, if you have a look at the class files produced, you'll find theres and A$B.class for each instance initialiser you've used. This doesn't matter in itself, but I did run into problems when I serialised one of my initialised lists. The problem is that the anonymous classes you're creating aren't static, and so contain a synthetic reference to the enclosing object. So, when you serialise your list, you also serialise everything in the class where you create it. Probably not what you wanted.
So yes, this is nice, and I use it a fair bit, but do take care.
--Robert
Posted by: Robert Chatley at December 28, 2006 7:24 PMYup. I tripped over this one in Dave Astels' TDD book, at a time when I thought I knew Java backwards and forwards...
http://home.comcast.net/~pholser/writings/concisions.html
I've used this in unit tests to prime collections, and for one-off things like command line option parsers from JOpt Simple (http://jopt-simple.sourceforge.net). But, like my article and the previous commenter mention, you do pay for the cute syntax with an extra anonymous class. For unit tests, no biggie. Sprinkled willy-nilly about the production source base -- be careful.
Posted by: Paul Holser at December 28, 2006 9:29 PMI documented this on the C2 wiki as one of the Java idioms. http://www.c2.com/cgi/wiki?DoubleBraceInitialization
Robert: that's a good point about serialisation. I've added that to the C2 page.
Posted by: Nat at December 28, 2006 10:07 PMYou should use this hack with real care because it creates an anonymous inner class. So, you are practically pollute VM heap with that garbage. Does it worth it?
Posted by: Eugene Kuleshov at December 29, 2006 4:21 AM>You should use this hack with real care because it creates an anonymous inner class. So, you are practically pollute VM heap with that garbage. Does it worth it?
anonymous inner class will pollute VM heap with that garbage?? Could anybody explain more about that? I use anonymous inner class A LOT
Posted by: Carfield Yim at December 29, 2006 9:48 AMThe commenter is mistaken. They don't pollute the heap any more than the new operator does. They *may* increase permspace, but classes should be garbage collected after their classloader is collected, only leaving their interned strings in permspace.
Posted by: Nat at December 29, 2006 1:16 PMBe aware that if you are happy to work with a java.util.List then you can just call:
List<String> list = Arrays.asList("hello", "world");
See http://java.sun.com/javase/6/docs/api/java/util/Arrays.html#asList(T...) for details.
Posted by: Keith at December 29, 2006 11:53 PMThe syntax is neat but one other side effect is that you'll get an extra lint warning because the anonymous class will tend to extend a class that implements Serialisable:
warning: [serial] serializable class has no definition of serialVersionUID
You also don't seem to be able to suppress serial warnings with @SuppressWarnings
Posted by: Anthony Gerrard at January 5, 2007 10:58 AMUGLY, UGLY, UGLY and hard to learn syntax...
Why not just
List hi = new ArrayList() {
"u", "r", "syntax", "looks", "fool"
};
this look like the array and will not be miss understand by novice.
Posted by: M. at January 17, 2007 6:01 PM