Watch out - double-brace initialization is cool looking, but it's orders of magnitude slower than regular initialization as it must generate an anonymous class.
Also, the generated class is put into the permgen space, which is not garbage collected. The permgen is pretty small by default - and if you fill it up, your system is hosed.
I use them all the time in unit tests, but never in production code.
The compiler generates the anonymous class. To the runtime, isn't it just a class with a name given to it by the compiler, not a developer (question mark...my key broke today)
It's true that it uses up permgen though, but if it only adds an initializer we're not talking about much space.
Edit:
I did an experiment. This is the code:
new ArrayList<Object>() {
{}
};
new ArrayList<Object>();
Here is the bytecode:
0 new Main$1 [16]
3 invokespecial Main$1() [18]
6 new java.util.ArrayList [19]
9 invokespecial java.util.ArrayList() [21]
And, the class:
class Main$1 extends java.util.ArrayList {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
Main$1();
0 aload_0 [this]
1 invokespecial java.util.ArrayList() [8]
4 return
Line numbers:
[pc: 0, line: 10]
[pc: 4, line: 1]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: new Main(){}
You can always copy and paste a question mark (?). I don't recommend coding that way, I once tried coding with the left quarter of the keyboard broken, not fun.
There is almost no speed hit the second time you create an instance of "Foo" with "Commonly", "Applied", and "Traits" applied. Not sure this would be useful for Java, although we can achieve the same effect as in the article.)
FWIW, this is all done in "user space". The metaclass instance is attached to every instance that it creates. When all the instances go away, there are no more references to the metaclass, and it gets reclaimed. The destructor handles deleting the symbol table entries that were added, and that's that.
There is something to be said for not baking things into the language.
This is one case where I really prefer C#'s approach; it supports a shortcut syntax (works on anything which implements IEnumerable and has a public Add method):
List<int> intList = new List<int>() { 1, 2, 3 };
which involves no anonymous classes or anything of the sort. The compiler merely "expands" it into the following before producing the bytecode:
List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
Which is, really, about what I'd expect such a shortcut syntax to do.
I think just generally you have to be aware that it is not a concrete ArrayList (or whatever) that is being created. You have to be careful about which classes you are anonymously subclassing. If the superclass has an equals method, for instance, that follows the getClass().equals(compare.getClass()) approach as part of its logic you are screwed.
. . . except that doesn't get you a modifiable list, it just wraps a List interface around the array that's implicitly created by the var-arg, so it's a trick you have to be careful with.
Personally I often end up writing little helpers like:
List<T> list(T... args) {
return new ArrayList<T>(Arrays.asList(args))
}
usually in test code. A built-in List and Map-initialization syntax is really something every decent programming language ought to have.
(Consider using the Google collections library if possible. It already has that in the form of classes like Lists, Maps, etc that provide builders and factory methods.)
I've been using this for years. It is a fantastic way to build up hierarchies. XML, maps, JSON, UI code etc. It is very concise, fast and produces clean code which also just happens to correctly indent when you apply code formatting.
School s = new School() {{
add(new Student() {{
name = "Bobby";
age = 15;
add(new Pet() {{
name = "Fluffy";
}});
}});
}};
vs.
School sc = new School();
Student st = new Student();
st.name = "Bobby";
st.age = 15;
Pet p = new Pet();
p.name = "Fluffy";
st.add(p);
sc.add(st);
One thing though. I love this technique but the home built Eclipse compiler is not fully Java language compliant and it will reject certain forms of this as invalid. Specifically, the sun and eclipse compiler treat "this" differently in these code blocks. My project will not compile under eclipse because of certain usages of this pattern when combined with inner classes. The bug crops up when you need to pass the parent to the child object being initialized in the static block.
Also, the generated class is put into the permgen space, which is not garbage collected. The permgen is pretty small by default - and if you fill it up, your system is hosed.
I use them all the time in unit tests, but never in production code.