This article is participating in the Java Theme Month – Java Debug Notes Event, see the event link for details
How efficient is Java “double parenthesis initialization”?
Among Java’s “hidden features”, the most common answer is Double Brace Initialization, whose syntax is seductive:
Set<String> flavors = new HashSet<String>() {{
add("vanilla");
add("strawberry");
add("chocolate");
add("butter pecan");
}};
Copy the code
This idiom creates an anonymous inner class that contains only one instance initializer that “can use any method in the contained scope.”
Main question: Does this sound like inefficiency? Should its use be limited to one-time initializations? (And showing off!)
Second problem: The new HashSet must be the “this” used in the instance initializer… Can anyone elucidate the mechanism?
Third question: Is this idiom too obscure to use in production code?
Very, very good answer, thank you. On issue (3), people think the syntax should be clear (although I recommend occasional comments, especially if your code is going to be passed on to developers who may not be familiar with it).
With regard to problem (1), the generated code should run quickly. Extra.class files do clutter up the JAR files and slow down the program startup a bit (thanks to @Coobird for measuring it). @Thilo points out that garbage collection can be affected, and in some cases, the memory cost of extra loaded classes can be a factor.
Question 2 is the most interesting to me. If I understand the answer, what is happening in DBI is that the anonymous inner class extends the class of the object constructed by the new operator and therefore has a value of “this” that refers to an instance of this construction. Very neat.
In general, DBI intrigues me. Coobird and others point out that you can achieve the same effect using arrays.aslist, the Varargs method, Google Collections, and the suggested Java 7 Collection text. Newer JVM languages (such as Scala, JRuby, and Groovy) also provide concise notations for list building and interoperate well with Java. Since DBI messes up the classpath, makes class loading slower, and makes code more opaque, I probably avoid it. However, I’m going to introduce this to a naturally funny friend who just got SCJP and loves Java semantics! ; -) Thank you!
7/2017: Baeldung has a good summary of double parenthesis initialization and considers it to be an anti-pattern.
12/2017: @basil Bourque points out that in the new Java 9 you can say:
Set flavors = Set.of(“vanilla”, “strawberry”, “chocolate”, “butter pecan”);
Answer:
This is my obsession with anonymous inner classes:
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 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 Class 2009/05/27 16:35926 DemoApp2$33$1$1.class 2009/05/27 16:354,104 DemoApp2$33$1.class 2009/05/27 16:35 2009/05/27 16:35926 DemoApp2$34$1$1.class 2009/05/27 16:354,234 DemoApp2$34$1.class 2009/05/27 16:352,849 DemoApp2$34.class /* snip */ 2009/05/27 16:35614 DemoApp2$40.class 2009/05/27 16:352,344 DemoApp2$5.class 2009/05/27 16:351,551 DemoApp2$6.class 2009/05/27 16:351,604 DemoApp2$7.class 2009/05/27 16:351,809 DemoApp2$8.class 2009/05/27 16:35 2,022 DemoApp2$9.classCopy the code
These are classes generated when you create a simple application and use a large number of anonymous inner classes – each of which will be compiled into a separate class file.
As mentioned earlier, a “double bracket initializer” is an anonymous inner class with an instance initializer block, which means that a new class will be created for each “initializer,” all usually to create a single object.
Considering that the Java virtual machine will need to read all of these classes when using them, this can lead to some time in the bytecode validation process. Not to mention the additional disk space needed to store all those class files.
Initialization with double parentheses seems to have some overhead, so thinking too much about it might not be a good idea. But as Eddie points out in his comments, it’s impossible to be absolutely sure of the impact.
For your information, here is the double parenthesis initialization:
List<String> list = new ArrayList<String>() {{ add("Hello"); add("World!" ); }};Copy the code
It looks like Java’s “hide” feature, but it’s just a rewrite of the following:
List<String> list = new ArrayList<String>() {
// Instance initialization block
{
add("Hello");
add("World!");
}
};
Copy the code
Therefore, it is basically an instance initialization block that is part of an anonymous inner class.
Joshua Bloch’s Collection Literals proposal for Project Coin goes something like this:
List<Integer> intList = [1, 2, 3, 4];
Set<String> strSet = {"Apple", "Banana", "Cactus"};
Map<String, Integer> truthMap = { "answer" : 42 };
Copy the code
Sadly, it didn’t make it into Java 7 and 8 and was shelved indefinitely.
The experiment
Here is the simple experiment I have tested – making 1000 elements of ArrayLists “Hello”, and “World!” By adding their add method, use two methods:
Method 1: Double parenthesis initialization
List<String> l = new ArrayList<String>() {{ add("Hello"); add("World!" ); }};Copy the code
Method 2: Instantiate an ArrayList and Add
List<String> l = new ArrayList<String>(); l.add("Hello"); l.add("World!" );Copy the code
I created a simple program to write out Java source files to perform 1000 initializations using two methods:
Test 1:
class Test1 { public static void main(String[] s) { long st = System.currentTimeMillis(); List<String> l0 = new ArrayList<String>() {{ add("Hello"); add("World!" ); }}; List<String> l1 = new ArrayList<String>() {{ add("Hello"); add("World!" ); }}; /* snip */ List<String> l999 = new ArrayList<String>() {{ add("Hello"); add("World!" ); }}; System.out.println(System.currentTimeMillis() - st); }}Copy the code
Test 2:
class Test2 { public static void main(String[] s) { long st = System.currentTimeMillis(); List<String> l0 = new ArrayList<String>(); l0.add("Hello"); l0.add("World!" ); List<String> l1 = new ArrayList<String>(); l1.add("Hello"); l1.add("World!" ); /* snip */ List<String> l999 = new ArrayList<String>(); l999.add("Hello"); l999.add("World!" ); System.out.println(System.currentTimeMillis() - st); }}Copy the code
Please note that after time initialize 1000 ArrayListS and 1000 anonymous inner classes extend ArrayList used to check System.CurrentTimemillis, so timer does not have very high resolution. On my Windows system, the resolution is about 15-16 milliseconds.
The results of the 10 runs of the two tests are as follows:
Test1 Times (ms) Test2 Times (ms)
---------------- ----------------
187 0
203 0
203 0
188 0
188 0
187 0
203 0
188 0
188 0
203 0
Copy the code
As you can see, the execution time of the double parenthesis initialization is about 190 milliseconds.
Meanwhile, ArrayList initialization execution time is 0 ms. Of course, you should consider the timer resolution, but it’s likely to be under 15 milliseconds.
Therefore, there seems to be a significant difference in execution time between the two methods. There does seem to be some overhead associated with these two initialization methods.
Yes,.class generated 1000 files by compiling the Test1 double brace initializer.
The article translated from am2dgbqfb6mk75jcyanzabc67y ac4c6men2g7xr2a – stackoverflow – com. Translate. Goog/questions / 9…
The authors suggest: This method is not recommended for initialization.
Thank you for reading this, if this article is well written and if you feel there is something to it
Ask for a thumbs up 👍 ask for attention ❤️ ask for share 👥 for 8 abs I really very useful!!
If there are any mistakes in this blog, please comment, thank you very much! ❤ ️ ❤ ️ ❤ ️ ❤ ️