跳转到内容

java 数组合并技巧详解,如何高效实现数组合并?

Java 数组合并通常有多种实现方式,主要包括:1、使用 System.arraycopy() 方法;2、利用 Arrays.copyOf() 或 Arrays.copyOfRange();3、通过流(Stream API)合并;4、手动遍历合并;5、借助第三方库如 Apache Commons Lang。 其中,System.arraycopy() 是效率最高且被广泛应用的方法之一,它能够直接将一个数组的全部或部分元素复制到另一个数组中,适用于基本数据类型和对象类型的数组。以 System.arraycopy() 为例,只需分配一个足够大的新数组,然后分别将两个原数组的数据拷贝进去即可,操作简洁高效,非常适合对性能有较高要求的场景。

《java 数组合并》


一、常用 Java 数组合并方法综述

Java 提供了多种方式实现数组合并,不同方法适用于不同场景。下表对主流方法做出比较:

方法是否原生性能是否支持泛型难度典型应用
System.arraycopy()很高支持简单大数据量合并
Arrays.copyOf()/copyOfRange支持简单部分数据合并
Stream.concat()是(JDK8+)中等支持简单函数式编程场景
手动遍历一般支持一般特殊逻辑处理
Apache Commons Lang否(需引入库)支持很简单企业级开发

二、System.arraycopy() 合并数组详解

System.arraycopy() 是 Java 标准库提供的高效数组拷贝工具,其语法如下:

System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

使用步骤

  1. 确定两个源数组及其长度。
  2. 创建目标数组,新长度为两者之和。
  3. 用 arraycopy 将第一个数组复制到目标数组前半部分。
  4. 用 arraycopy 将第二个数组复制到目标数组后半部分。

示例代码

int[] arr1 = \{1, 2, 3\};
int[] arr2 = \{4, 5\};
int[] result = new int[arr1.length + arr2.length];
System.arraycopy(arr1, 0, result, 0, arr1.length);
System.arraycopy(arr2, 0, result, arr1.length, arr2.length);
// result: [1, 2, 3, 4, 5]

优缺点

  • 优点:操作系统底层优化,性能极高,代码简洁,适用所有一维基本类型或对象类型。
  • 缺点:不能处理多维嵌套结构,要手动分配新空间,不支持动态扩容。

三、Arrays.copyOf()/copyOfRange 用于合并与扩展

Arrays 工具类是 Java 常用的集合辅助类,其 copyOf 和 copyOfRange 方法可快速扩展或部分合并。

步骤与示例

int[] a = \{10,20\};
int[] b = \{30,-5\};
int[] merged = Arrays.copyOf(a,a.length+b.length);
System.arraycopy(b,0,merged,a.length,b.length);
// merged: [10,20,30,-5]

或者借助 copyOfRange 多步拼接:

int[] merged = new int[a.length + b.length];
merged = Arrays.copyOf(a,a.length+b.length);
for(int i=0; i<b.length; i++) \{
merged[a.length+i]=b[i];
\}

对比分析

  • 优点:代码简明,更适合不可变对象创建需求。
  • 缺点:仍需调用多行代码实现完整拼接,对性能有微小影响。

四、Java8 Stream.concat 合并任意类型/长度的数组

自 JDK8 起,Stream API 支持函数式风格编程,对象和基本类型都能方便地进行组合与处理。

示例代码

// 对象型
String[] s1 = \{"a", "b"\};
String[] s2 = \{"c", "d"\};
String[] combined = Stream.concat(Arrays.stream(s1), Arrays.stream(s2))
.toArray(String[]::new);
// 基本类型需转装箱流
int[] n1=\{3\}, n2=\{7\};
int[] combinedInts=IntStream.concat(Arrays.stream(n1),Arrays.stream(n2)).toArray();

特点及应用场景

  • 优点:链式操作,易于集成过滤、去重等复杂逻辑,更加灵活通用。
  • 缺点:对大量数据存在额外开销(装箱/拆箱),性能略低于 arraycopy。

五、手动遍历方式与特殊逻辑处理需求

实际开发中,有时需要根据业务规则灵活拼接,如条件过滤或跳过重复项,这时可采用手动遍历:

步骤说明

  • 新建目标数组或 ArrayList;
  • 按规则循环插入元素;
  • 可结合 if 判断实现更复杂逻辑。

示例表格:常见自定义规则流程

步骤操作
Step1定义新集合(如 ArrayList 或新整型组)
Step2遍历第一个原始组,将元素逐个添加
Step3遍历第二组,可按条件决定是否添加
Step4转换为最终所需的静态类型(如 toArray)

这种方案最灵活,但最耗费人工编码时间和资源调优,只建议在标准方式无法满足需求时使用。


六、使用第三方库如 Apache Commons Lang 的 ArrayUtils 合并工具类

对于企业级项目或希望简化模板代码,可以直接引入成熟第三方工具类。例如 Apache Commons Lang 的 ArrayUtils:

示例代码

import org.apache.commons.lang3.ArrayUtils;
int[] a=\{9\},b=\{88,-6\};
int[] merged=ArrayUtils.addAll(a,b); // [9,88,-6]

特性总结

  • 优点:

  • 极大减少样板代码,无需关心底层细节;

  • 能直接支持 null 安全、防止 NPE;

  • 可统一处理基本类型及对象型;

  • 缺点:

  • 增加依赖包体积;

  • 存在版本兼容性风险;

此法更倾向大型企业项目和框架化开发场景,但不适用于对 jar 包体积极度敏感的小型项目或嵌入式设备等环境。


七、多维与泛型数据结构的合并考量及注意事项

在面对多维/嵌套结构或泛型时,需要注意:

  • 多维只能按“行”一级一级复制,不可整体直接 arraycopy;
  • 泛型受限于 Java 类型擦除机制,如 T extends Object,在运行期只保留 Object 信息,应确保目标容器声明为具体实例化类型;
  • 若涉及深拷贝,则每层都要递归复制,否则仅是引用拼接;

多维拼接伪码示例

// 假设二维整形矩阵 a[][] 和 b[][] 行数分别为 m,n,列数一致:
int totalRows=a.length+b.length;
int[][] merged=new int[totalRows][];
for(int i=0;i<a.length;i++) merged[i]=Arrays.copyOf(a[i],a[i].length);
for(int j=0;j<b.length;j++) merged[a.length+j]=Arrays.copyOf(b[j],b[j].length);

这种写法确保每个子行都是独立副本,可避免引用相互干扰的问题。


八、不同方案优劣汇总与应用建议表格整理

下表以实际开发角度分析各主流方法优劣,并给出推荐场景:

| 场景 | 推荐方法 | 性能 | 易用性 | |--------------------- --- -------------------------- --- --------------------| | 简单基础一维整形组 系统 arraycopy 极优 优 | | 大量对象/字符串组 Arrays.copyOf+arraycopy 良好 良 | | 双向链式/条件筛选需求 JDK8 Stream.concat 中 极佳 | | 个性化特殊业务规则 自定义循环 一般 灵活(复杂) | | 项目已有第三方依赖包 ArrayUtils.addAll 良好 极佳 |

如果追求最佳执行效率且仅需要简单无损拼接,请首选 System.arraycopy,如果倾向于易读性和灵活表达,可以考虑 Stream 和工具包方案。如果同时涉及复杂业务流程,则自定义循环是唯一选择。


九、安全性与异常处理方面的补充说明

无论采用哪种方式,都应特别注意以下安全问题:

  • 空指针防护: 合并前判断源组非 null,否则容易抛出 NullPointerException;
  • 长度越界: 分配目标组空间必须保证是两者之和,不然会出现 IndexOutofBoundsException;
  • 线程安全: 如多个线程同时修改合成结果,需要额外加锁同步保护。
  • 内存溢出: 超大规模数据建议分批次批量处理,否则可能触发 OOM 错误;

健壮开发习惯应提前预防上述潜在风险,并做好异常捕获及回退机制设计。


十、小结与实战建议行动清单

综上所述,在 Java 中进行数组合并时,可根据具体项目需求从以下几个步骤着手:

  1. 明确待合并的数据规模与实时性能要求; 2. 优先采用 System.arraycopy 或 Arrays 工具类完成基础任务; 3. 若涉及复杂筛选/映射则可借助 Stream API 实现链式操作; 4. 项目已引入大型通用库则可以充分利用第三方工具包减少重复造轮子工作量; 5. 注意边界条件校验,加强异常保护,提高系统健壮性;

最后建议结合实际工程背景测试不同方法下的执行效率,并根据团队技术栈偏好进行最优选择。如追求极致速度推荐原生 arraycopy,如强调维护便利则倾向流式写法或成熟框架工具,这样才能兼顾可靠、高效以及易维护三者之间平衡,实现最佳开发实践。

精品问答: