在Java中如何合并两个List集合_Java集合合并操作说明

最直接合并两个List的方式是调用目标可变列表的addAll()方法,它将源列表元素追加到目标末尾且不修改源列表;注意目标列表须为ArrayList等可变类型,否则抛UnsupportedOperationException。

addAll() 合并两个 List

最直接

Java 中合并两个 List,最常用、最安全的方式就是调用目标列表的 addAll() 方法。它会把源列表所有元素追加到目标列表末尾,不改变源列表本身。

注意:目标列表必须是可变的(比如 ArrayList),不能是 Collections.unmodifiableList()Arrays.asList() 返回的固定大小列表,否则运行时抛出 UnsupportedOperationException

  • 如果目标列表是新创建的空列表,适合做“无副作用合并”
  • 如果目标列表已有数据,addAll() 是就地修改,原对象内容会变
  • 源列表和目标列表类型需兼容(如都是 List),否则编译报错
List list1 = new ArrayList<>(Arrays.asList("a", "b"));
List list2 = Arrays.asList("c", "d"); // 不可变,但可作为源
list1.addAll(list2); // ✅ 正确:list1 变成 ["a", "b", "c", "d"]

合并时去重?用 Stream + distinct() 更可控

原生 addAll() 不去重。若需要合并后唯一元素,推荐用 Stream 流式处理,尤其在 Java 8+ 环境下。

关键点:必须确保元素实现了 equals()hashCode()(对自定义对象尤其重要),否则 distinct() 无法正确识别重复项。

  • Stream.concat() 可连接两个流,再链式调用 distinct()collect()
  • 结果默认是 ArrayList,但顺序保持原始插入顺序(LinkedHashSet 语义)
  • 性能上比手动遍历 contains() 高,尤其数据量大时
List a = Arrays.asList(1, 2, 3);
List b = Arrays.asList(2, 3, 4);
List merged = Stream.concat(a.stream(), b.stream())
    .distinct()
    .collect(Collectors.toList()); // [1, 2, 3, 4]

CollectionUtils.union() 看似方便,但要注意 Apache Commons 版本差异

Apache Commons Collections 的 CollectionUtils.union() 能直接返回去重后的合并结果,但它返回的是 Collection 接口类型,不是 List,且行为因版本而异:

  • 3.x 版本中,union() 返回的是 Set(无序),即使输入是 List
  • 4.4+ 版本新增了 CollectionUtils.unionAsList(),才保证返回 List 并保留顺序
  • 依赖第三方库意味着增加包体积和潜在冲突,简单场景不建议只为合并引入 Commons

如果你已在项目中使用 Commons 且版本 ≥ 4.4,可以这样写:

List result = CollectionUtils.unionAsList(list1, list2);

避免踩坑:不要用 Arrays.asList() 直接合并

常见错误是想“一行合并”,于是写:Arrays.asList(list1, list2) —— 这实际创建了一个包含两个 List 引用的 List>,根本不是元素级合并。

另一个陷阱是误用 Arrays.asList() 包装数组后调用 addAll():它返回的是固定大小列表,addAll() 会失败。

  • Arrays.asList("x", "y") 返回不可扩容列表,add()addAll() 抛异常
  • 要安全操作,先套一层 new ArrayList()
  • 泛型通配符(如 List extends Number>)会导致 addAll() 编译失败,需显式转型或改用原始类型

合并逻辑越简单,越该用原生 API;复杂需求(如按字段合并、差集、交集)再考虑 Guava 或 Commons。