1. 概述
对于任何 Java 开发者来说,在处理数组操作时,写出干净、高效的代码并不总是那么容易。但数组在 Java 生态中却是核心组件之一,我们不可避免地会频繁与它们打交道。
因此,拥有一份“速查手册”——总结最常见的数组操作,对我们快速解决相关问题大有帮助。本文就是为这种场景准备的。
2. 数组与辅助类
在继续之前,我们有必要了解 Java 中的数组是什么,以及如何使用它。如果你是初次接触 Java 数组,建议先阅读 这篇基础指南,其中涵盖了所有基本概念。
需要注意的是,数组本身支持的基本操作是有限的。在数组操作中,我们常常看到为了完成简单任务而不得不使用复杂算法的情况。
✅ 因此,大多数操作我们都会借助 Java 提供的辅助类和方法:Arrays
类和 Apache 的 ArrayUtils
类。
如果要在项目中使用后者,我们需要添加 Apache Commons 依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
你可以随时在 Maven Central 上查看该依赖的最新版本。
3. 获取数组的第一个和最后一个元素
这是最常见、也最简单的任务之一,得益于数组支持按索引访问的特性。
我们先声明并初始化一个 int
数组,用于后续示例(除非特别说明):
int[] array = new int[] { 3, 5, 2, 5, 14, 4 };
由于数组的第一个元素索引为 0
,并且数组有 length
属性,因此获取首尾元素非常简单:
int firstItem = array[0];
int lastItem = array[array.length - 1];
4. 获取数组中的随机元素
借助 java.util.Random
对象,我们可以轻松获取数组中的任意元素:
int anyValue = array[new Random().nextInt(array.length)];
5. 向数组追加新元素
我们知道,数组的大小是固定的,无法直接添加新元素。
✅ 所以我们要先创建一个更大的新数组,再将原数组的元素复制过去。
幸运的是,Java 的 Arrays
类提供了一个便捷方法来完成这个任务:
int[] newArray = Arrays.copyOf(array, array.length + 1);
newArray[newArray.length - 1] = newItem;
⚠️ 如果项目中引入了 ArrayUtils
,我们可以使用其 add
方法(或 addAll
)来一行搞定:
int[] newArray = ArrayUtils.add(array, newItem);
注意:该方法不会修改原数组,而是返回一个新数组,需要赋值给新变量。
6. 在两个元素之间插入值
由于数组是基于索引的数据结构,插入元素并不简单。
✅ Apache 提供了 ArrayUtils.insert
方法来简化操作:
int[] largerArray = ArrayUtils.insert(2, array, 77);
📌 需要指定插入位置的索引,返回的是一个新数组。
最后一个参数是可变参数(vararg),所以可以一次插入多个元素。
7. 比较两个数组
虽然数组是 Object
,并提供了 equals
方法,但它使用的是默认实现,只比较引用。
✅ 我们可以调用 java.util.Arrays.equals
方法来比较两个数组的内容是否相同:
boolean areEqual = Arrays.equals(array1, array2);
⚠️ 注意:此方法不适用于 锯齿数组(jagged arrays)。对于多维数组,应使用 Arrays.deepEquals
方法。
8. 判断数组是否为空
利用数组的 length
属性,判断是否为空非常简单:
boolean isEmpty = array == null || array.length == 0;
✅ 如果引入了 ArrayUtils
,还可以使用其 null-safe 方法:
boolean isEmpty = ArrayUtils.isEmpty(array);
⚠️ 但要注意,该方法仍然依赖 length
属性,对于以下情况需额外注意:
// 以下数组被认为是空的
Integer[] array1 = {};
Integer[] array2 = null;
Integer[] array3 = new Integer[0];
// 以下数组不会被认为是空的
Integer[] array4 = { null, null, null };
Integer[][] array5 = { {}, {}, {} };
Integer[] array6 = new Integer[3];
9. 打乱数组元素顺序
✅ 使用 ArrayUtils.shuffle
方法可以轻松打乱数组:
ArrayUtils.shuffle(array);
📌 这是一个 void
方法,会直接修改原数组。
10. 装箱与拆箱数组
我们常常会遇到只接受 Object
类型数组的方法。
✅ ArrayUtils
提供了便捷方法用于装箱:
Integer[] list = ArrayUtils.toObject(array);
同样支持反向操作:
Integer[] objectArray = { 3, 5, 2, 5, 14, 4 };
int[] array = ArrayUtils.toPrimitive(objectArray);
11. 去除数组中的重复元素
✅ 最简单的方法是将数组转换为 Set
:
// 装箱
Integer[] list = ArrayUtils.toObject(array);
// 去重
Set<Integer> set = new HashSet<>(Arrays.asList(list));
// 创建数组并拆箱
return ArrayUtils.toPrimitive(set.toArray(new Integer[set.size()]));
📌 如果需要保持顺序,建议使用 LinkedHashSet
。
12. 打印数组内容
数组的 toString()
方法使用的是 Object
默认实现,输出并不直观。
✅ Arrays
和 ArrayUtils
都提供了专用方法:
String arrayAsString = ArrayUtils.toString(array);
📌 Apache 的 toString
方法支持所有类型数组,而 Java 的 Arrays.toString()
不支持原始类型多维数组。
13. 数组映射为另一种类型
✅ 通过泛型,我们可以编写一个通用的映射方法:
public static <T, U> U[] mapObjectArray(
T[] array, Function<T, U> function,
Class<U> targetClazz) {
U[] newArray = (U[]) Array.newInstance(targetClazz, array.length);
for (int i = 0; i < array.length; i++) {
newArray[i] = function.apply(array[i]);
}
return newArray;
}
📌 如果没有 Java 8,可以去掉 Function
,为每种映射写专门的方法。
也可以使用 Java 8 的 Stream 实现:
String[] stringArray = Arrays.stream(array)
.mapToObj(value -> String.format("Value: %s", value))
.toArray(String[]::new);
14. 过滤数组中的元素
✅ 使用 Stream 可以方便地过滤数组元素:
int[] evenArray = Arrays.stream(array)
.filter(value -> value % 2 == 0)
.toArray();
📌 因为数组大小固定,所以过滤操作更适合使用 Stream。
15. 其他常见数组操作
除了上述内容,还有很多常见操作我们也在其他文章中详细讲解过:
- 检查数组是否包含某个值
- 如何复制数组
- 删除数组的第一个元素
- 查找数组中的最大最小值
- 计算数组的和与平均值
- 反转数组
- 数组与集合的合并与拆分
- 组合不同类型的集合
- 找出数组中和为指定值的所有数对
- 排序
- 高效词频统计
- 插入排序
16. 总结
数组是 Java 的核心功能之一,理解其工作原理和操作方式至关重要。
本文总结了在常见场景下如何高效处理数组操作。
完整代码示例可在 GitHub 仓库 中找到。