patternjavaCritical
Efficiency of Java "Double Brace Initialization"?
Viewed 0 times
doublebracejavaefficiencyinitialization
Problem
In Hidden Features of Java the top answer mentions Double Brace Initialization, with a very enticing syntax:
This idiom creates an anonymous inner class with just an instance initializer in it, which "can use any [...] methods in the containing scope".
Main question: Is this as inefficient as it sounds? Should its use be limited to one-off initializations? (And of course showing off!)
Second question: The new HashSet must be the "this" used in the instance initializer ... can anyone shed light on the mechanism?
Third question: Is this idiom too obscure to use in production code?
Summary: Very, very nice answers, thanks everyone. On question (3), people felt the syntax should be clear (though I'd recommend an occasional comment, especially if your code will pass on to developers who may not be familiar with it).
On question (1), the generated code should run quickly. The extra .class files do cause jar file clutter, and slow program startup slightly (thanks to @coobird for measuring that). @Thilo pointed out that garbage collection can be affected, and the memory cost for the extra loaded classes may be a factor in some cases.
Question (2) turned out to be most interesting to me. If I understand the answers, what's happening in DBI is that the anonymous inner class extends the class of the object being constructed by the new operator, and hence has a "this" value referencing the instance being constructed. Very neat.
Overall, DBI strikes me as something of an intellectual curiousity. Coobird and others point out you can achieve the same effect with Arrays.asList, varargs methods, Google Collections, and the proposed Java 7 Collection literals. Newer JVM languages like Scala, JRuby, and Groovy also offer concise notations for list construction, and interoperate well with Java. Given that DBI clutters up the classpat
Set flavors = new HashSet() {{
add("vanilla");
add("strawberry");
add("chocolate");
add("butter pecan");
}};This idiom creates an anonymous inner class with just an instance initializer in it, which "can use any [...] methods in the containing scope".
Main question: Is this as inefficient as it sounds? Should its use be limited to one-off initializations? (And of course showing off!)
Second question: The new HashSet must be the "this" used in the instance initializer ... can anyone shed light on the mechanism?
Third question: Is this idiom too obscure to use in production code?
Summary: Very, very nice answers, thanks everyone. On question (3), people felt the syntax should be clear (though I'd recommend an occasional comment, especially if your code will pass on to developers who may not be familiar with it).
On question (1), the generated code should run quickly. The extra .class files do cause jar file clutter, and slow program startup slightly (thanks to @coobird for measuring that). @Thilo pointed out that garbage collection can be affected, and the memory cost for the extra loaded classes may be a factor in some cases.
Question (2) turned out to be most interesting to me. If I understand the answers, what's happening in DBI is that the anonymous inner class extends the class of the object being constructed by the new operator, and hence has a "this" value referencing the instance being constructed. Very neat.
Overall, DBI strikes me as something of an intellectual curiousity. Coobird and others point out you can achieve the same effect with Arrays.asList, varargs methods, Google Collections, and the proposed Java 7 Collection literals. Newer JVM languages like Scala, JRuby, and Groovy also offer concise notations for list construction, and interoperate well with Java. Given that DBI clutters up the classpat
Solution
Here's the problem when I get too carried away with anonymous inner classes:
These are all classes which were generated when I was making a simple application, and used copious amounts of anonymous inner classes -- each class will be compiled into a separate
The "double brace initialization", as already mentioned, is an anonymous inner class with an instance initialization block, which means that a new class is created for each "initialization", all for the purpose of usually making a single object.
Considering that the Java Virtual Machine will need to read all those classes when using them, that can lead to some time in the bytecode verfication process and such. Not to mention the increase in the needed disk space in order to store all those
It seems as if there is a bit of overhead when utilizing double-brace initialization, so it's probably not such a good idea to go too overboard with it. But as Eddie has noted in the comments, it's not possible to be absolutely sure of the impact.
Just for reference, double brace initialization is the following:
It looks like a "hidden" feature of Java, but it is just a rewrite of:
So it's basically a instance initialization block that is part of an anonymous inner class.
Joshua Bloch's Collection Literals proposal for Project Coin was along the lines of:
Sadly, it didn't make its way into neither Java 7 nor 8 and was shelved indefinitely.
Experiment
Here's the simple experiment I've tested -- make 1000
Method 1: Double Brace Initialization
Method 2: Instantiate an
I created a simple program to write out a Java source file to perform 1000 initializations using the two methods:
Test 1:
Test 2:
Please note, that the elapsed time to initialize the 1000
The results for 10 runs of the two tests were the following:
```
Test1 Times (ms) Test2 Times (ms)
---------------- ----------------
187 0
203 0
203 0
188 0
188 0
187 0
2009/05/27 16:35 1,602 DemoApp2$1.class
2009/05/27 16:35 1,976 DemoApp2$10.class
2009/05/27 16:35 1,919 DemoApp2$11.class
2009/05/27 16:35 2,404 DemoApp2$12.class
2009/05/27 16:35 1,197 DemoApp2$13.class
/* snip */
2009/05/27 16:35 1,953 DemoApp2$30.class
2009/05/27 16:35 1,910 DemoApp2$31.class
2009/05/27 16:35 2,007 DemoApp2$32.class
2009/05/27 16:35 926 DemoApp2$33$1$1.class
2009/05/27 16:35 4,104 DemoApp2$33$1.class
2009/05/27 16:35 2,849 DemoApp2$33.class
2009/05/27 16:35 926 DemoApp2$34$1$1.class
2009/05/27 16:35 4,234 DemoApp2$34$1.class
2009/05/27 16:35 2,849 DemoApp2$34.class
/* snip */
2009/05/27 16:35 614 DemoApp2$40.class
2009/05/27 16:35 2,344 DemoApp2$5.class
2009/05/27 16:35 1,551 DemoApp2$6.class
2009/05/27 16:35 1,604 DemoApp2$7.class
2009/05/27 16:35 1,809 DemoApp2$8.class
2009/05/27 16:35 2,022 DemoApp2$9.classThese are all classes which were generated when I was making a simple application, and used copious amounts of anonymous inner classes -- each class will be compiled into a separate
class file.The "double brace initialization", as already mentioned, is an anonymous inner class with an instance initialization block, which means that a new class is created for each "initialization", all for the purpose of usually making a single object.
Considering that the Java Virtual Machine will need to read all those classes when using them, that can lead to some time in the bytecode verfication process and such. Not to mention the increase in the needed disk space in order to store all those
class files.It seems as if there is a bit of overhead when utilizing double-brace initialization, so it's probably not such a good idea to go too overboard with it. But as Eddie has noted in the comments, it's not possible to be absolutely sure of the impact.
Just for reference, double brace initialization is the following:
List list = new ArrayList() {{
add("Hello");
add("World!");
}};It looks like a "hidden" feature of Java, but it is just a rewrite of:
List list = new ArrayList() {
// Instance initialization block
{
add("Hello");
add("World!");
}
};So it's basically a instance initialization block that is part of an anonymous inner class.
Joshua Bloch's Collection Literals proposal for Project Coin was along the lines of:
List intList = [1, 2, 3, 4];
Set strSet = {"Apple", "Banana", "Cactus"};
Map truthMap = { "answer" : 42 };Sadly, it didn't make its way into neither Java 7 nor 8 and was shelved indefinitely.
Experiment
Here's the simple experiment I've tested -- make 1000
ArrayLists with the elements "Hello" and "World!" added to them via the add method, using the two methods:Method 1: Double Brace Initialization
List l = new ArrayList() {{
add("Hello");
add("World!");
}};Method 2: Instantiate an
ArrayList and addList l = new ArrayList();
l.add("Hello");
l.add("World!");I created a simple program to write out a Java source file to perform 1000 initializations using the two methods:
Test 1:
class Test1 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List l0 = new ArrayList() {{
add("Hello");
add("World!");
}};
List l1 = new ArrayList() {{
add("Hello");
add("World!");
}};
/* snip */
List l999 = new ArrayList() {{
add("Hello");
add("World!");
}};
System.out.println(System.currentTimeMillis() - st);
}
}Test 2:
class Test2 {
public static void main(String[] s) {
long st = System.currentTimeMillis();
List l0 = new ArrayList();
l0.add("Hello");
l0.add("World!");
List l1 = new ArrayList();
l1.add("Hello");
l1.add("World!");
/* snip */
List l999 = new ArrayList();
l999.add("Hello");
l999.add("World!");
System.out.println(System.currentTimeMillis() - st);
}
}Please note, that the elapsed time to initialize the 1000
ArrayLists and the 1000 anonymous inner classes extending ArrayList is checked using the System.currentTimeMillis, so the timer does not have a very high resolution. On my Windows system, the resolution is around 15-16 milliseconds.The results for 10 runs of the two tests were the following:
```
Test1 Times (ms) Test2 Times (ms)
---------------- ----------------
187 0
203 0
203 0
188 0
188 0
187 0
Code Snippets
2009/05/27 16:35 1,602 DemoApp2$1.class
2009/05/27 16:35 1,976 DemoApp2$10.class
2009/05/27 16:35 1,919 DemoApp2$11.class
2009/05/27 16:35 2,404 DemoApp2$12.class
2009/05/27 16:35 1,197 DemoApp2$13.class
/* snip */
2009/05/27 16:35 1,953 DemoApp2$30.class
2009/05/27 16:35 1,910 DemoApp2$31.class
2009/05/27 16:35 2,007 DemoApp2$32.class
2009/05/27 16:35 926 DemoApp2$33$1$1.class
2009/05/27 16:35 4,104 DemoApp2$33$1.class
2009/05/27 16:35 2,849 DemoApp2$33.class
2009/05/27 16:35 926 DemoApp2$34$1$1.class
2009/05/27 16:35 4,234 DemoApp2$34$1.class
2009/05/27 16:35 2,849 DemoApp2$34.class
/* snip */
2009/05/27 16:35 614 DemoApp2$40.class
2009/05/27 16:35 2,344 DemoApp2$5.class
2009/05/27 16:35 1,551 DemoApp2$6.class
2009/05/27 16:35 1,604 DemoApp2$7.class
2009/05/27 16:35 1,809 DemoApp2$8.class
2009/05/27 16:35 2,022 DemoApp2$9.classList<String> list = new ArrayList<String>() {{
add("Hello");
add("World!");
}};List<String> list = new ArrayList<String>() {
// Instance initialization block
{
add("Hello");
add("World!");
}
};List<Integer> intList = [1, 2, 3, 4];
Set<String> strSet = {"Apple", "Banana", "Cactus"};
Map<String, Integer> truthMap = { "answer" : 42 };List<String> l = new ArrayList<String>() {{
add("Hello");
add("World!");
}};Context
Stack Overflow Q#924285, score: 658
Revisions (0)
No revisions yet.