这段代码中的 new ArrayList<Object>() {{ ... }}
是一种特殊的语法,称为 双括号初始化(Double Brace Initialization)。它结合了匿名内部类和实例初始化块的特性,用于快速创建并初始化一个集合对象(如 ArrayList
)。下面我们来详细分析为什么这种写法会放在这个位置,以及它的作用。
1. 为什么放在这个位置?
在这段代码中:
List<Map<String, Object>> tableList = queryTool.query(tableQuery, new ArrayList<Object>() {{
add(datasource.getDatabaseName());
if (StringUtils.isNotEmpty(oldTableName)) {
add(oldTableName);
}
}});
-
queryTool.query
方法的第二个参数:- 从方法签名来看,
queryTool.query
的第二个参数是一个List<Object>
类型。 - 这里需要传递一个
ArrayList<Object>
对象作为参数。
- 从方法签名来看,
-
new ArrayList<Object>() {{ ... }}
的作用:- 使用双括号初始化的方式,可以快速创建一个
ArrayList
对象,并在创建的同时向其中添加元素。 - 这种写法避免了先创建一个空的
ArrayList
,然后再通过多次调用add()
方法添加元素的繁琐操作。
- 使用双括号初始化的方式,可以快速创建一个
因此,这段代码直接在方法调用的位置创建了一个包含所需元素的 ArrayList
,并将其作为参数传递给 queryTool.query
方法。
2. 双括号初始化的工作原理
(1) 外层括号:匿名内部类
new ArrayList<Object>() { ... }
创建了一个匿名内部类,继承自ArrayList<Object>
。- 由于没有定义任何新的方法或覆盖现有方法,这个匿名内部类的行为与普通的
ArrayList
完全一致。
(2) 内层括号:实例初始化块
- 内层的
{{ ... }}
是一个 实例初始化块(Instance Initializer Block)。 - 实例初始化块会在对象构造时执行,类似于构造函数中的代码。
- 在这里,
add(datasource.getDatabaseName())
和add(oldTableName)
是在对象创建时立即执行的操作。
等价代码
如果不使用双括号初始化,这段代码可以改写为以下形式:
List<Object> params = new ArrayList<>();
params.add(datasource.getDatabaseName());
if (StringUtils.isNotEmpty(oldTableName)) {
params.add(oldTableName);
}
List<Map<String, Object>> tableList = queryTool.query(tableQuery, params);
可以看到,双括号初始化是一种更简洁的写法,但它的本质是相同的。
3. 为什么选择双括号初始化?
优点
-
简洁性:
- 直接在创建对象的同时完成初始化,减少了代码量。
- 特别适合在需要传递临时集合对象的场景中使用。
-
可读性:
- 对于简单的初始化操作,双括号初始化可以让代码看起来更加紧凑。
缺点
-
性能开销:
- 双括号初始化实际上创建了一个匿名内部类,这会导致额外的类加载和内存占用。
- 对于频繁调用的场景,可能会对性能产生一定影响。
-
序列化问题:
- 匿名内部类会持有外部类的引用,如果将这个集合对象用于序列化(如存储到文件或通过网络传输),可能会导致意外的序列化问题。
-
维护性:
- 如果初始化逻辑较复杂,双括号初始化可能会降低代码的可读性和可维护性。
4. 替代方案
如果担心双括号初始化的性能问题或潜在风险,可以使用传统的写法,例如:
(1) 显式创建并初始化
List<Object> params = new ArrayList<>();
params.add(datasource.getDatabaseName());
if (StringUtils.isNotEmpty(oldTableName)) {
params.add(oldTableName);
}
List<Map<String, Object>> tableList = queryTool.query(tableQuery, params);
(2) 使用 Java 9+ 的 List.of
或 Stream
如果不需要修改集合内容,可以使用不可变集合(Java 9+ 提供的 List.of
方法):
List<Object> params = Stream.of(
datasource.getDatabaseName(),
StringUtils.isNotEmpty(oldTableName) ? oldTableName : null
)
.filter(Objects::nonNull)
.collect(Collectors.toList());
List<Map<String, Object>> tableList = queryTool.query(tableQuery, params);
5. 总结
- 双括号初始化 是一种方便的语法糖,用于快速创建并初始化集合对象。
- 在这段代码中,
new ArrayList<Object>() {{ ... }}
的作用是直接在方法调用的位置创建一个包含所需元素的ArrayList
,并将其作为参数传递给queryTool.query
方法。 - 尽管双括号初始化简洁高效,但在性能敏感或需要序列化的场景中,建议使用传统的写法或现代的集合工具(如
List.of
或Stream
)。