
ArrayUtils 是 Apache Commons Lang 中用于处理数组的工具类。它把 Java 数组中常见但繁琐的操作封装成了一组 public static 方法,适合用于数组创建、查询、修改、转换、判空、排序判断等场景。
本文基于 Apache Commons Lang ArrayUtils 3.20.0,对其能力按功能分类进行整理。文中的示例来自 ArrayUtilsTest 中的代表性测试用例。
从功能上看,ArrayUtils 主要覆盖以下 12 类能力:
null 处理Map 表示按唯一方法名统计,ArrayUtils 共有 44 个 public static 方法名。需要注意的是,这里统计的是唯一方法名,不是全部重载。由于 ArrayUtils 对基本类型数组、包装类型数组、对象数组都提供了大量重载,实际 public static 重载数量远多于唯一方法名。
ArrayUtils 提供了大量空数组常量,用于复用空数组对象,避免重复创建 new int[0]、new String[0] 这类对象。
常见常量包括:
EMPTY_BOOLEAN_ARRAYEMPTY_BYTE_ARRAYEMPTY_CHAR_ARRAYEMPTY_DOUBLE_ARRAYEMPTY_FLOAT_ARRAYEMPTY_INT_ARRAYEMPTY_LONG_ARRAYEMPTY_SHORT_ARRAYEMPTY_OBJECT_ARRAY这些常量适合在方法返回空结果时使用。例如,当一个方法需要返回空数组而不是 null 时,可以直接返回对应的 EMPTY_*_ARRAY。
assertNotNull(ArrayUtils.EMPTY_BOOLEAN_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_BOOLEAN_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_BYTE_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_BYTE_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_CHAR_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_CHAR_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_DOUBLE_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_DOUBLE_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_FLOAT_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_FLOAT_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_INT_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_INT_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_LONG_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_LONG_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_SHORT_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_SHORT_ARRAY.length);
assertNotNull(ArrayUtils.EMPTY_OBJECT_ARRAY);
assertEquals(0, ArrayUtils.EMPTY_OBJECT_ARRAY.length);INDEX_NOT_FOUNDINDEX_NOT_FOUND 的值固定为 -1,用于表示查找失败。
它常见于 indexOf、lastIndexOf 等查找方法的返回值中,语义类似 String.indexOf 返回 -1。
assertEquals(-1, ArrayUtils.INDEX_NOT_FOUND);这一类方法用于基于原数组创建新数组,并向其中添加一个或多个元素。
addadd 用于复制原数组,并在末尾或指定位置添加一个元素。
典型使用场景:
null 数组添加元素,得到一个单元素数组int[] result = ArrayUtils.add(new int[]{1}, 2);
assertArrayEquals(new int[]{1, 2}, result);
result = ArrayUtils.add((int[]) null, 1);
assertArrayEquals(new int[]{1}, result);addFirstaddFirst 用于复制数组,并在数组开头添加一个元素。
final int[] array = new int[]{1, 2};
final int[] result = ArrayUtils.addFirst(array, 0);
assertArrayEquals(new int[]{0, 1, 2}, result);addAlladdAll 用于合并两个数组。
典型使用场景:
null 的情况final int[] array1 = new int[]{1, 2};
final int[] array2 = new int[]{3};
int[] result = ArrayUtils.addAll(array1, array2);
assertArrayEquals(new int[]{1, 2, 3}, result);
result = ArrayUtils.addAll(null, array2);
assertArrayEquals(array2, result);
result = ArrayUtils.addAll(array1, (int[]) null);
assertArrayEquals(array1, result);insertinsert 用于在指定索引位置插入一个或多个元素。
它和 add(array, index, element) 的区别在于:
add 更偏向插入单个元素insert 更偏向批量插入多个值final int[] array = new int[]{1, 3};
final int[] result = ArrayUtils.insert(1, array, 2);
assertArrayEquals(new int[]{1, 2, 3}, result);这一类方法用于从数组中删除指定元素或指定索引,并返回删除后的新数组。
removeremove 用于删除指定索引位置的元素。
final int[] array = new int[]{1, 2, 3};
final int[] result = ArrayUtils.remove(array, 1);
assertArrayEquals(new int[]{1, 3}, result);removeAllremoveAll 用于删除多个指定索引位置的元素。
final int[] array = new int[]{1, 2, 3, 4};
final int[] result = ArrayUtils.removeAll(array, 1, 3);
assertArrayEquals(new int[]{1, 3}, result);removeElementremoveElement 用于删除第一个匹配的元素。
如果数组中存在多个相同元素,它只删除第一次出现的那个。
final int[] array = new int[]{1, 2, 2, 3};
final int[] result = ArrayUtils.removeElement(array, 2);
assertArrayEquals(new int[]{1, 2, 3}, result);removeElementsremoveElements 用于按给定元素删除对应匹配项。
它不是简单地删除所有匹配元素,而是按照传入元素的数量进行删除。
final int[] array = new int[]{1, 2, 2, 3, 3};
final int[] result = ArrayUtils.removeElements(array, 2, 3);
assertArrayEquals(new int[]{1, 2, 3}, result);removeAllOccurrencesremoveAllOccurrences 用于删除数组中所有匹配的元素。
final int[] array = new int[]{1, 2, 2, 3};
final int[] result = ArrayUtils.removeAllOccurrences(array, 2);
assertArrayEquals(new int[]{1, 3}, result);removeAllOccurencesremoveAllOccurences 是 removeAllOccurrences 的旧拼写兼容方法。
注意:Occurences 少了一个 r。它的语义与 removeAllOccurrences 相同,主要用于兼容旧代码。
final int[] array = new int[]{1, 2, 2, 3};
final int[] result = ArrayUtils.removeAllOccurences(array, 2);
assertArrayEquals(new int[]{1, 3}, result);这一类方法用于判断元素是否存在,以及查找元素出现的位置。
containscontains 用于判断数组是否包含指定元素。
final int[] array = new int[]{1, 2, 3};
assertTrue(ArrayUtils.contains(array, 2));
assertFalse(ArrayUtils.contains(array, 5));
assertFalse(ArrayUtils.contains((int[]) null, 1));containsAnycontainsAny 用于判断数组是否包含任意一个给定元素。
final int[] array = new int[]{1, 2, 3};
assertTrue(ArrayUtils.containsAny(array, 1, 5));
assertFalse(ArrayUtils.containsAny(array, 4, 5));indexOfindexOf 用于查找元素第一次出现的位置。
部分重载支持指定起始索引。
final int[] array = new int[]{1, 2, 3, 2};
assertEquals(0, ArrayUtils.indexOf(array, 1));
assertEquals(1, ArrayUtils.indexOf(array, 2));
assertEquals(-1, ArrayUtils.indexOf(array, 5));lastIndexOflastIndexOf 用于查找元素最后一次出现的位置。
部分重载支持从指定位置向前查找。
final int[] array = new int[]{1, 2, 3, 2};
assertEquals(3, ArrayUtils.lastIndexOf(array, 2));
assertEquals(-1, ArrayUtils.lastIndexOf(array, 5));indexesOfindexesOf 用于查找元素出现的所有位置,并返回 BitSet。
它适合需要一次获取全部匹配索引的场景。
final int[] array = new int[]{1, 2, 3, 2};
final BitSet result = ArrayUtils.indexesOf(array, 2);
assertTrue(result.get(1));
assertTrue(result.get(3));
assertEquals(2, result.cardinality());startsWithstartsWith 用于判断一个 byte[] 是否以另一个 byte[] 作为前缀。
final byte[] data = new byte[]{1, 2, 3};
assertTrue(ArrayUtils.startsWith(data, new byte[]{1, 2}));
assertFalse(ArrayUtils.startsWith(data, new byte[]{2, 3}));这一类方法用于读取数组中的元素信息、长度信息和类型信息。
getget 用于按索引获取数组元素。
常见语义:
null 或指定默认值final String[] array = new String[]{"a", "b", "c"};
assertEquals("a", ArrayUtils.get(array, 0));
assertEquals("c", ArrayUtils.get(array, 2));
assertNull(ArrayUtils.get(array, 5));getLengthgetLength 用于获取数组长度。
如果输入为 null,返回 0。
final int[] array = new int[]{1, 2};
assertEquals(2, ArrayUtils.getLength(array));
assertEquals(0, ArrayUtils.getLength(null));getComponentTypegetComponentType 用于获取数组的组件类型。
final String[] array = new String[]{"a", "b"};
assertEquals(String.class, ArrayUtils.getComponentType(array));newInstancenewInstance 用于根据组件类型和长度创建新数组。
final String[] result = ArrayUtils.newInstance(String.class, 2);
assertEquals(2, result.length);
assertEquals(String.class, result.getClass().getComponentType());这一类方法用于判断数组是否为空、长度是否一致、类型是否一致、内容是否相等,以及是否有序。
isEmptyisEmpty 用于判断数组是否为 null 或长度为 0。
assertTrue(ArrayUtils.isEmpty((Object[]) null));
assertTrue(ArrayUtils.isEmpty(new int[0]));
assertFalse(ArrayUtils.isEmpty(new int[]{1}));isNotEmptyisNotEmpty 用于判断数组是否非 null 且长度大于 0。
assertFalse(ArrayUtils.isNotEmpty((Object[]) null));
assertFalse(ArrayUtils.isNotEmpty(new int[0]));
assertTrue(ArrayUtils.isNotEmpty(new int[]{1}));isSameLengthisSameLength 用于判断两个数组长度是否相同。
final int[] array1 = new int[]{1, 2};
final int[] array2 = new int[]{3, 4};
assertTrue(ArrayUtils.isSameLength(array1, array2));
assertFalse(ArrayUtils.isSameLength(array1, new int[]{1}));isSameTypeisSameType 用于判断两个数组类型是否相同。
final int[] array1 = new int[]{1, 2};
final int[] array2 = new int[]{3, 4};
assertTrue(ArrayUtils.isSameType(array1, array2));isEqualsisEquals 用于判断两个数组内容是否相等。
该方法在当前版本中已标记为 deprecated,但仍可用于理解历史 API。
final int[] array1 = new int[]{1, 2};
final int[] array2 = new int[]{1, 2};
assertTrue(ArrayUtils.isEquals(array1, array2));isSortedisSorted 用于判断数组是否已经排序。
常见重载包括:
Comparator 判断final int[] sorted = new int[]{1, 2, 3};
final int[] unsorted = new int[]{3, 1, 2};
assertTrue(ArrayUtils.isSorted(sorted));
assertFalse(ArrayUtils.isSorted(unsorted));isArrayIndexValidisArrayIndexValid 用于判断索引是否是数组的有效索引。
有效索引满足:
0 <= index < array.length测试中可以看到,null 数组不会拥有有效索引:
final String[] array = new String[]{"a", "b"};
assertTrue(ArrayUtils.isArrayIndexValid(array, 0));
assertTrue(ArrayUtils.isArrayIndexValid(array, 1));
assertFalse(ArrayUtils.isArrayIndexValid(array, 2));
assertFalse(ArrayUtils.isArrayIndexValid(null, 0));这一类方法用于创建数组副本,或复制数组中的一段内容。
cloneclone 用于克隆数组。
语义:
null 数组返回内容相同但引用不同的新数组null 输入返回 nullfinal int[] array = new int[]{1, 2};
final int[] result = ArrayUtils.clone(array);
assertArrayEquals(array, result);
assertNotSame(array, result);
assertNull(ArrayUtils.clone((int[]) null));subarraysubarray 用于获取数组切片。
这里的区间语义是 [startIndexInclusive, endIndexExclusive)。
final int[] array = new int[]{1, 2, 3, 4};
final int[] result = ArrayUtils.subarray(array, 1, 3);
assertArrayEquals(new int[]{2, 3}, result);arraycopyarraycopy 是对 System.arraycopy 的流式封装。
它复制数组片段,并返回目标数组,适合希望链式使用复制结果的场景。
final int[] source = new int[]{1, 2, 3};
final int[] destination = new int[]{0, 0, 0};
final int[] result = ArrayUtils.arraycopy(source, 1, destination, 0, 2);
assertSame(destination, result);
assertArrayEquals(new int[]{2, 3, 0}, destination);null 处理这一类方法用于把 null 数组转换成更安全的默认值。
nullToEmptynullToEmpty 用于将 null 数组转换为空数组。
如果输入数组非 null,则返回原数组引用。
int[] result = ArrayUtils.nullToEmpty((int[]) null);
assertNotNull(result);
assertEquals(0, result.length);
final int[] array = new int[]{1, 2};
result = ArrayUtils.nullToEmpty(array);
assertSame(array, result);nullTonullTo 用于在数组为 null 时返回指定默认数组;否则返回原数组。
它适合为数组参数提供默认值。
final String[] defaultArray = new String[]{"default"};
final String[] array = new String[]{"value"};
assertSame(defaultArray, ArrayUtils.nullTo(null, defaultArray));
assertSame(array, ArrayUtils.nullTo(array, defaultArray));这一类方法用于改变数组中元素的排列顺序。
reversereverse 用于反转数组元素顺序。
它支持反转整个数组,也支持反转指定范围。
final int[] array = new int[]{1, 2, 3};
ArrayUtils.reverse(array);
assertArrayEquals(new int[]{3, 2, 1}, array);shiftshift 用于循环位移数组元素。
final int[] array = new int[]{1, 2, 3, 4};
ArrayUtils.shift(array, 1);
assertArrayEquals(new int[]{4, 1, 2, 3}, array);swapswap 用于交换数组中两个位置的元素。
部分重载支持交换两个区间。
final int[] array = new int[]{1, 2, 3};
ArrayUtils.swap(array, 0, 2);
assertArrayEquals(new int[]{3, 2, 1}, array);shuffleshuffle 用于随机打乱数组顺序。
测试这类方法时,不应断言固定顺序。更合理的方式是:
Random 控制随机源final int[] array = new int[]{1, 2, 3, 4};
ArrayUtils.shuffle(array, new Random(1));
final int[] sorted = ArrayUtils.clone(array);
Arrays.sort(sorted);
assertArrayEquals(new int[]{1, 2, 3, 4}, sorted);setAllsetAll 用于通过生成函数批量设置数组元素。
常见重载包括:
IntFunction,根据索引生成值Supplier,每次调用生成一个值它适合需要按规则初始化数组的场景。
final String[] array = new String[3];
final String[] result = ArrayUtils.setAll(array, index -> "v" + index);
assertSame(array, result);
assertArrayEquals(new String[]{"v0", "v1", "v2"}, array);这一类方法用于在基本类型数组、包装类型数组、对象数组和字符串数组之间转换。
toObjecttoObject 用于将基本类型数组转换为包装类型数组。
final Integer[] result = ArrayUtils.toObject(new int[]{1, 2, 3});
assertArrayEquals(new Integer[]{1, 2, 3}, result);toPrimitivetoPrimitive 用于将包装类型数组转换为基本类型数组。
部分重载支持为 null 元素指定默认值。
final Integer[] array = new Integer[]{1, 2, 3};
final int[] result = ArrayUtils.toPrimitive(array);
assertArrayEquals(new int[]{1, 2, 3}, result);toArraytoArray 用于将可变参数作为数组返回。
它适合简化数组创建表达式。
final String[] result = ArrayUtils.toArray("a", "b", "c");
assertArrayEquals(new String[]{"a", "b", "c"}, result);toStringArraytoStringArray 用于将对象数组转换为字符串数组。
部分重载支持指定 null 元素的替代文本。
final Object[] array = new Object[]{"a", 1, null};
final String[] result = ArrayUtils.toStringArray(array, "NULL");
assertArrayEquals(new String[]{"a", "1", "NULL"}, result);Map 表示这一类方法用于把数组转换为字符串表示、计算哈希值,或把数组形式的数据转换为 Map。
toStringtoString 用于获取数组的字符串表示,支持嵌套数组。
部分重载支持数组为 null 时返回指定字符串。
final int[] array = new int[]{1, 2, 3};
final String result = ArrayUtils.toString(array);
assertNotNull(result);
assertTrue(result.contains("1"));hashCodehashCode 用于获取数组的哈希码,并能正确处理多维数组。
final int[] array = new int[]{1, 2, 3};
final int code = ArrayUtils.hashCode(array);
assertNotEquals(0, code);toMaptoMap 用于将数组形式的数据转换为 Map。
支持的元素形式包括:
Map.EntryObject[],其中第一个元素作为 key,第二个元素作为 valuefinal Object[] array = new Object[]{new Object[]{"a", 1}, new Object[]{"b", 2}};
final Map<Object, Object> result = ArrayUtils.toMap(array);
assertEquals(1, result.get("a"));
assertEquals(2, result.get("b"));由于 ArrayUtils 的重载非常多,如果对每个重载都写完整测试,测试数量会非常庞大,也容易淹没教程重点。
更适合教程项目的测试策略是:
shuffle 等随机行为避免断言固定顺序,优先验证元素集合不变。按照该策略,测试既能展示完整 API 面,又不会因为大量重复重载而降低可读性。
ArrayUtils 的核心价值,是把 Java 数组操作中常见的样板代码封装成稳定、统一的工具方法。
如果按使用场景理解,可以把它记成几组能力:
add、addFirst、addAll、insertremove、removeAll、removeElement、removeElements、removeAllOccurrencescontains、containsAny、indexOf、lastIndexOf、indexesOfisEmpty、isNotEmpty、isSameLength、isSameType、isSortedclone、subarray、arraycopynull:看 nullToEmpty、nullToreverse、shift、swap、shuffletoObject、toPrimitive、toArray、toStringArray这样理解之后,ArrayUtils 不再是一长串 API 列表,而是一组围绕数组生命周期展开的工具能力。