What is Double Brace initialization in Java?
Java中的双括号初始化语法( {{ ... }}
)是什么?
Double brace initialisation creates an anonymous class derived from the specified class (the outer braces), and provides an initialiser block within that class (the inner braces). eg
new ArrayList<Integer>() {{
add(1);
add(2);
}};
Note that an effect of using this double brace initialisation is that you're creating anonymous inner classes. The created class has an implicit this
pointer to the surrounding outer class. Whilst not normally a problem, it can cause grief in some circumstances eg when serialising or garbage collecting, and it's worth being aware of this.
Every time someone uses double brace initialisation, a kitten gets killed.
Apart from the syntax being rather unusual and not really idiomatic (taste is debatable, of course), you are unnecessarily creating two significant problems in your application, which I've just recently blogged about in more detail here.
1. You're creating way too many anonymous classes
Each time you use double brace initialisation a new class is made. Eg this example:
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
... will produce these classes:
Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class
That's quite a bit of overhead for your classloader - for nothing! Of course it won't take much initialisation time if you do it once. But if you do this 20'000 times throughout your enterprise application... all that heap memory just for a bit of "syntax sugar"?
2. You're potentially creating a memory leak!
If you take the above code and return that map from a method, callers of that method might be unsuspectingly holding on to very heavy resources that cannot be garbage collected. Consider the following example:
public class ReallyHeavyObject {
// Just to illustrate...
private int[] tonsOfValues;
private Resource[] tonsOfResources;
// This method almost does nothing
public Map quickHarmlessMethod() {
Map source = new HashMap(){{
put("firstName", "John");
put("lastName", "Smith");
put("organizations", new HashMap(){{
put("0", new HashMap(){{
put("id", "1234");
}});
put("abc", new HashMap(){{
put("id", "5678");
}});
}});
}};
return source;
}
}
The returned Map
will now contain a reference to the enclosing instance of ReallyHeavyObject
. You probably don't want to risk that:
Image from http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/
3. You can pretend that Java has map literals
To answer your actual question, people have been using this syntax to pretend that Java has something like map literals, similar to the existing array literals:
String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};
Some people may find this syntactically stimulating.
For example:
public class TestHashMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<String,String>(){
{
put("1", "ONE");
}{
put("2", "TWO");
}{
put("3", "THREE");
}
};
Set<String> keySet = map.keySet();
for (String string : keySet) {
System.out.println(string+" ->"+map.get(string));
}
}
}
How it works
First brace creates a new Anonymous Inner Class. These inner classes are capable of accessing the behavior of their parent class. So, in our case, we are actually creating a subclass of HashSet class, so this inner class is capable of using add() method.
And Second set of braces are nothing but instance initializers. If you remind core java concepts then you can easily associate instance initializer blocks with static initializers due to similar brace like struct. Only difference is that static initializer is added with static keyword, and is run only once; no matter how many objects you create.
more
链接地址: http://www.djcxy.com/p/82398.html