List.addAll()是Java中高效批量添加集合元素的首选方法,底层采用System.arraycopy等优化机制,优于逐个add()和Stream.concat;需确保目标列表可变、预扩容避免性能损耗,并注意null及类型安全。

List.addAll() 是 Java 中将一个集合的所有元素批量添加到另一个列表的最常用方法,它底层直接调用数组复制(如 System.arraycopy)或批量迭代,比逐个调用 add() 效率更高,尤其适合中大型数据集。
确保目标列表支持添加操作
并非所有 List 实现都允许修改。例如:
-
Arrays.asList()返回的是固定大小列表,调用addAll()会抛出UnsupportedOperationException; -
Collections.unmodifiableList()包装的列表也不可变; - 应优先使用可变实现,如
ArrayList、LinkedList或new CopyOnWriteArrayList()(多线程场景)。
注意容量与扩容开销
ArrayList 在内部数组不足时会触发扩容(默认 1.5 倍增长),频繁扩容影响性能。若已知待添加元素数量,建议预先扩容:
ArrayList<String> target = new ArrayList<>(); target.ensureCapacity(target.size() + source.size()); // 预留空间 target.addAll(source);
这能避免多次数组复制,提升批量合并效率。
立即学习“Java免费学习笔记(深入)”;
处理 null 和类型安全
addAll() 不校验元素是否为 null(除非目标列表实现禁止 null,如某些自定义封装),也不做泛型运行时检查。需确保:
- 源集合不包含与目标列表泛型不兼容的类型(编译期可捕获,但反射或原始类型操作可能绕过);
- 若业务逻辑不允许 null,应在合并前过滤:
source.stream().filter(Objects::nonNull).collect(Collectors.toList()); - 对不可信输入,建议先做类型/空值校验再调用
addAll()。
替代方案对比:addAll() vs 手动循环 vs Stream.concat
在大多数场景下,addAll() 是最优解:
- 比
for-each + add()少一次方法调用开销,且底层常优化为批量内存拷贝; - 比
Stream.concat(a, b).collect(...)开销更小——后者创建中间流对象、涉及函数式接口调用和新集合分配; - 若需去重或转换,
addAll()不适用,此时应选stream().distinct()或map().filter()等组合操作。


















