Poison

Double Brace Initialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package me.tianshuang;

import java.util.HashMap;
import java.util.Map;

public class DoubleBraceTest {

private static Map<String, String> map = new HashMap<String, String>() {{
put("key1", "value1");
put("key2", "value2");
put("key3", "value3");
}};

}

以上代码使用了双括号初始化,其中外层那一对括号创建了一个匿名内部类,里层的那一对括号是一个实例初始化块。对于上面这一段源码,进行编译后我们可以在目录看到两个 class 文件,分别是 DoubleBraceTest.classDoubleBraceTest$1.class,其中 DoubleBraceTest$1.class 是我们定义的 HashMap 类的匿名子类,其反编译源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package me.tianshuang;

import java.util.HashMap;

final class DoubleBraceTest$1 extends HashMap<String, String> {
DoubleBraceTest$1() {
this.put("key1", "value1");
this.put("key2", "value2");
this.put("key3", "value3");
}
}

记录这个问题是因为同事编写了如下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package me.tianshuang;

import java.util.HashMap;
import java.util.Map;

public class DoubleBraceTest {

private static Map<String, String> map = new HashMap<String, String>() {{
map.put("key1", "value1");
map.put("key2", "value2");
map.put("key3", "value3");
}};

public static void main(String[] args) {
DoubleBraceTest doubleBraceTest = new DoubleBraceTest();
}

}

触发了 java.lang.ExceptionInInitializerError,原因为匿名内部类实例初始化块中触发了空指针异常,上面这段代码编译时并不会报错,运行时抛出异常。估计同事编写上面这段代码是因为对双括号初始化块实现机制不清楚,所以写出了上述代码。

在日常使用中还是应该避免此种写法,一是因为是通过匿名内部类实现,二是因为此写法不易读。

References

What is Double Brace initialization in Java? - Stack Overflow
Java Double Brace Initialization | Baeldung