一、概述
1.1 工具简介
ArrayUtil(数组工具类)是 Hutool 针对原始类型数组和泛型数组相关方法进行封装,解决对象数组(包括包装类型数组)和原始类型数组使用方法不统一的问题,提供了对数组的常用操作。它最大的价值在于消除对象数组与原始类型数组 API 不一致的痛点,用同一套方法处理任意数组,例如数组的判空、数组的合并、数组的截取等。
1.2 引入依赖
在使用 Hutool 工具之前,需要将 Hutool 添加到项目的依赖中。如果使用 Maven 构建项目,可以在 pom.xml 文件中添加以下依赖:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
Hutool-all 是一个 Hutool 的集成打包产品,由于考虑到"懒人"用户及分不清各个模块作用的用户,"无脑"引入 hutool-all 模块是快速开始和深入应用的最佳方式。如果你想像 SpringBoot 一样引入 Hutool,再由子模块决定用到哪些模块,你可以在父模块中加入:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-bom</artifactId>
<version>${hutool.version}</version>
<type>pom</type>
<!-- 注意这里是import -->
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
然后再在子模块中就可以引入自己需要的模块了:
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
</dependencies>
二、基础操作:判空与创建
原生数组的判空和泛型创建比较麻烦,ArrayUtil 提供了标准的解决方法。
2.1 判空与校验
数组的"空"有两种不同层次的含义,ArrayUtil 提供了对应的判断方法:
graph LR
A["数组判空"]
A-->A1["null 判断:数组本身为 null 或元素含 null"]
A-->A2["empty 判断:数组为 null 或长度为 0"]
null 相关判断
方法
说明
hasNull(array)
判断数组中是否包含 null 元素,数组本身为 null 时也返回 true
isAllNull(array)
判断数组中所有元素是否全部为 null
isAllNotNull(array)
判断数组中所有元素是否全部不为 null
firstNonNull(array)
查找并返回数组中第一个非 null 元素
String[] a = {"a", null, "b"};
System.out.println("判断数组中是否包含 null 元素:" + ArrayUtil.hasNull(a));
String[] b = {null, null, null};
System.out.println("判断数组是否所有元素都为 null:" + ArrayUtil.isAllNull(b));
String[] c = {"a", "b", "c"};
System.out.println("判断数组是否所有元素都不为 null:" + ArrayUtil.isAllNotNull(c));
String[] d = {null, null, "first", null, "second"};
System.out.println("获取数组中第一个非 null 元素:" + ArrayUtil.firstNonNull(d));
empty 判断
ArrayUtil 判断规则:null 或者数组长度为 0 → 为空,它同时支持原始类型(如 int\[\])和泛型数组,避免了手动写 array == null || array.length == 0 。
方法
说明
isEmpty(array)
判断数组是否为空(null 或长度为 0)
isNotEmpty(array)
判断数组是否非空,与 isEmpty 互为反操作
hasEmpty(array)
判断数组中是否包含空元素,覆盖 null、空集合、空 Map、空数组等
isAllEmpty(array)
是否全都为 null 或空对象
isAllNotEmpty(array)
是否全都不为 null 或空对象
defaultIfEmpty(array, defaultArray)
如果给定数组为空,返回默认数组
emptyCount(array)
计算数组中空元素的个数
int[] a = {};
System.out.println("判断数组是否为空(null 或长度为 0):" + ArrayUtil.isEmpty(a));
int[] b = null;
System.out.println("判断数组是否为空(null 或长度为 0):" + ArrayUtil.isEmpty(b));
String[] c = {"a", "b"};
System.out.println("判断数组是否为空(null 或长度为 0):" + ArrayUtil.isEmpty(c));
int[] d = {1, 2, 3};
System.out.println("判断数组是否不为空(不为 null 且长度大于 0):" + ArrayUtil.isNotEmpty(d));
String[] e = {"", "a", "b"};
System.out.println("判断数组是否包含空值:" + ArrayUtil.hasEmpty(e));
Object[] f = {"a", new ArrayList<>()};
System.out.println("判断数组是否包含空值:" + ArrayUtil.hasEmpty(f));
System.out.println("是否存都为null或空对象:" + ArrayUtil.isAllEmpty(e));
System.out.println("是否存都为null或空对象:" + ArrayUtil.isAllNotEmpty(e));
String[] result = ArrayUtil.defaultIfEmpty(new String[0], new String[]{"default"});
System.out.println("给定数组为空,返回默认数组" + ArrayUtil.toString(result));
Object[] arr = {"a", new ArrayList<>(), new HashMap<>(), new int[0]};
System.out.println("统计数组中空值的数量:" + ArrayUtil.emptyCount(arr));
2.2 数组创建与初始化
方法
说明
newArray(componentType, length)
创建指定类型和长度的泛型数组 ,封装了 JDK 的 Array.newInstance 方法
range(start, end, step)
生成有序整数数组,支持步进参数
getArrayType(array)
根据数组元素类型,获取数组的类型
getComponentType(componentType)
获取数组对象的元素类型
cast(type,arrayObj)
强转数组类型,前提是元素类型可被强制转换,会生成新数组
String[] arr = ArrayUtil.newArray(String.class, 3);
System.out.println("创建 String 数组:" + Arrays.toString(arr));
Object[] arr2 = ArrayUtil.newArray(5);
System.out.println("创建 Object 数组:" + Arrays.toString(arr2));
int[] a = ArrayUtil.range(5);
System.out.println("创建 int 数组:" + Arrays.toString(a));
int[] b = ArrayUtil.range(2, 7);
System.out.println("创建 int 数组:" + Arrays.toString(b));
int[] c = ArrayUtil.range(0, 10, 2);
System.out.println("创建 int 数组:" + Arrays.toString(c));
三、元素基本操作
3.1 获取元素
方法
说明
get(array, index)
获取指定位置的元素,支持负数索引(-1 表示最后一个元素)。 如果数组下标越界,返回null
getAny(array, indexes)
获取数组中指定多个下标的元素,组成新数组返回
String[] arr = {"a", "b", "c", "d"};
Object first = ArrayUtil.get(arr, 0);
System.out.println("获取第一个元素:" + first);
Object last = ArrayUtil.get(arr, -1);
System.out.println("获取最后一个元素:" + last);
Object secondLast = ArrayUtil.get(arr, -2);
System.out.println("获取倒数第二个元素:" + secondLast);
String[] result01 = ArrayUtil.getAny(arr, 10);
System.out.println("获取第10个元素:" + ArrayUtil.toString(result01));
String[] result02 = ArrayUtil.getAny(arr, 0, 2, 4);
System.out.println("获取第0个、第2个、第4个元素:" + ArrayUtil.toString(result02));
3.2 追加元素
方法
说明
append(array, elements)
将新元素追加到已有数组末尾,生成新数组,不影响原数组
String[] a = {"1", "2", "3"};
String[] result = ArrayUtil.append(a, "4", "5");
System.out.println(ArrayUtil.toString(result));
3.3 设置与替换
方法
说明
setOrAppend(array, index, value)
设置指定位置的元素值。如果 index 大于等于数组长度,则追加元素
setOrPadding(array, index, value)
强制设置指定位置的元素值,超出部分用默认值填充
replace(array, index, values)
从指定位置开始,用新元素替换旧元素。 index < 0 时在头部插入,index>= 长度时在尾部追加。 index + 新元素数 > 长度时生成新数组,否则在原数组中替换并返回
int[] arr = {1, 2, 3};
int[] result = ArrayUtil.setOrAppend(arr, 1, 99);
int[] result2 = ArrayUtil.setOrAppend(arr, 5, 99);
String[] arr = new String[0];
String[] result = ArrayUtil.setOrPadding(arr, 2, "Good");
String[] result2 = ArrayUtil.setOrPadding(arr, 2, "Good", "pad");
String[] a = {"1", "2", "3", "4"};
String[] b = {"a", "b", "c"};
ArrayUtil.replace(a, 0, b); // ["a", "b", "c", "4"]
ArrayUtil.replace(a, 1, b); // ["1", "a", "b", "c"]
ArrayUtil.replace(a, 2, b); // ["1", "2", "a", "b", "c"]
ArrayUtil.replace(a, 4, b); // ["1", "2", "3", "4", "a", "b", "c"]
ArrayUtil.replace(a, -1, b); // ["a", "b", "c", "1", "2", "3", "4"]
3.4 插入元素
方法
说明
insert(array, index, values)
在指定位置插入元素,返回新数组,不影响原数组。 index 为负数则从后向前计数,大于数组长度则空白处用 null 填充
String[] a = {"1", "2", "3", "4"};
String[] b = {"x", "y"};
System.out.println("原数组:" + ArrayUtil.toString(a));
System.out.println("从头部插入结果:" + ArrayUtil.toString(ArrayUtil.insert(a, 2, b)));
System.out.println("从尾部插入结果:" + ArrayUtil.toString(ArrayUtil.insert(a, -3, b)));
System.out.println("指定位置插入结果:" + ArrayUtil.toString(ArrayUtil.insert(a, 9, "9")));
3.5 移除元素
方法
说明
remove(array, index)
移除数组中指定位置的元素,生成新数组,原数组不变
removeEle(array, element)
移除数组中指定的元素,生成新数组。如有多个匹配,只移除第一个
removeBlank(T\[\] array)
批量移除数组中的 null 或者 "" 或者空白字符串元素,生成新数组
removeEmpty(T\[\] array)
批量移除数组中的 null或者 "" 元素,生成新数组
removeNull(T\[\] array)
批量移除数组中的 null 元素,生成新数组
String[] arr01 = {"a", "b", "c", "d"};
String[] result01 = ArrayUtil.remove(arr01, 1);
Integer[] arr02 = {1, 2, 3, 2, 4};
Integer[] result02 = ArrayUtil.removeEle(arr02, 2);
3.6 调整大小
方法
说明
resize(array, newSize)
重新调整数组大小,生成新数组 。 新数组大小小于原数组时截断,大于时用默认值 0 填充。
String[] stringArr = ArrayUtil.newArray(String.class, 3);
String[] bigger = ArrayUtil.resize(stringArr, 5);
System.out.println("原数组长度:" + stringArr.length + ",新数组长度:" + bigger.length);
3.7 替换元素
方法
说明
replace(array, index, newElements)
从指定位置开始,用新元素替换旧元素。 位置为负数时在头部插入,超出长度时在尾部追加
nullToEmpty
将数组元素中的 null 转换为空字符串 ""
String[] a = {"1", "2", "3", "4"};
String[] b = {"x", "y", "z"};
// 从位置 1 开始替换
String[] result = ArrayUtil.replace(a, 1, b);
// ["1", "x", "y", "z"]
// 位置为负,相当于头部插入
String[] result2 = ArrayUtil.replace(a, -1, b);
// ["x", "y", "z", "1", "2", "3", "4"]
四、查找与判断
4.1 查找与索引
方法
说明
indexOf(array, value)
查找指定元素在数组中第一次出现的位置,未找到返回 -1
indexOf(array, value, beginIndexInclude)
指定元素在数组中 beginIndexInclude 以后第一次出现的位置
lastIndexOf(array, value)
查找指定元素在数组中最后一次出现的位置,未找到返回 -1
matchIndex(predicate, array)
查找满足条件的第一个元素的索引位置,未找到返回 null
firstMatch(predicate, array)
查找满足条件的第一个元素并返回,未找到返回 null
indexOfIgnoreCase
返回数组中指定元素所在位置,忽略大小写
Integer[] arr = {1, 2, 3, 4, 3, 6};
int index01 = ArrayUtil.indexOf(arr, 3);
System.out.println("查找指定元素在数组中第一次出现的位置:" + index01);
int index02 = ArrayUtil.lastIndexOf(arr, 3);
System.out.println("查找指定元素在数组中最后一次出现的位置:" + index02);
int index03 = ArrayUtil.matchIndex(v -> v > 3, arr);
System.out.println("查找第一个符合条件的元素的索引:" + index03);
Integer result = ArrayUtil.firstMatch(v -> v > 15, arr);
System.out.println("查找第一个符合条件的元素:" + result);
4.2 包含与判断
方法
说明
contains(array, value)
通过 equals 方法判断数组中是否包含指定元素
containsAny(array, values)
通过 equals 方法判断数组中是否包含指定元素中的任意一个
containsAll(array, values)
通过 equals 方法判断数组中是否包含所有指定元素
containsIgnoreCase(array, value)
判断字符串数组中是否包含指定元素,忽略大小写
equals(array1, array2)
判断两个数组是否相等,判断依据包括数组长度和每个元素都相等。 自动识别类型,无需强制转换
isArray(obj)
判断对象是否为数组对象
Integer[] arr = {1, 2, 3, 4, 5};
boolean result = ArrayUtil.contains(arr, 3);
System.out.println("数组中是否包含指定元素:" + result);
boolean containsAnyResult = ArrayUtil.containsAny(arr, 4, 10, 40);
System.out.println("数组中是否包含指定元素中的任意一个:" + containsAnyResult);
boolean containsAllResult = ArrayUtil.containsAll(arr, 2, 4, 5);
System.out.println("数组中是否包含指定元素中的所有:" + containsAllResult);
String[] keys = {"a", "B", "c"};
boolean containsIgnoreCaseResult = ArrayUtil.containsIgnoreCase(keys, "b");
System.out.println("数组中是否包含指定元素b(忽略大小写):" + containsIgnoreCaseResult);
boolean equalsResult = ArrayUtil.equals(new int[]{1, 2, 3}, new int[]{1, 2, 3});
System.out.println("数组是否相等:" + equalsResult);
boolean isArrayResult = ArrayUtil.isArray(new int[]{1, 2, 3}); // true
System.out.println("是否为数组:" + isArrayResult);
boolean isArrayResult2 = ArrayUtil.isArray("hello"); // false
System.out.println("是否为数组:" + isArrayResult2);
五、过滤、编辑与转换
5.1 过滤与编辑
方法
说明
edit(array, editor)
对数组元素进行编辑,返回新数组。 通过 Editor 函数处理每个元素,返回 null 则过滤掉该元素
filter(array, filter)
使用 Filter 接口过滤数组元素,返回 true 表示保留
Integer[] arr = {1, 2, 3, 4, 5, 6};
// 偶数乘以 10,奇数不变
Integer[] result = ArrayUtil.edit(arr, t -> (t % 2 == 0) ? t * 10 : t);
// 只保留偶数
Integer[] even = ArrayUtil.edit(arr, t -> (t % 2 == 0) ? t : null);
// 只保留偶数
Integer[] even = ArrayUtil.filter(arr, t -> t % 2 == 0);
Editor 是 Hutool 提供的函数式接口,接收一个参数并返回修改后的值,返回 null 表示过滤掉该元素,在 Java 8+ 中可以直接使用 Lambda 表达式。
5.2 类型转换
拆装箱
方法
说明
wrap(primitiveArray)
将原始类型数组转换为包装类型数组,如 int\[\] → Integer\[\]
unWrap(wrapperArray)
将包装类型数组转换为原始类型数组,如 Integer\[\] → int\[\]
int[] primitive = {1, 2, 3, 4};
Integer[] wrapped = ArrayUtil.wrap(primitive);
Integer[] wrapped = {1, 2, 3, 4};
int[] primitive = ArrayUtil.unWrap(wrapped);
map 转换
方法
说明
map(array, targetType, mapper)
将数组元素转换为其他类型,支持自定义转换规则。 参数为 Object,支持原始类型数组
mapToArray(array, mapper, generator)
按照指定规则,将泛型数组的元素转换为另一种类型的数组
mapToList(array, mapper)
按照指定规则,将数组元素转换后收集为 List
mapToSet(array, mapper)
按照指定规则,将数组元素转换后收集为 Set(自动去重)
int[] arr = {1, 2, 3};
Integer[] result = ArrayUtil.map(arr, Integer.class, t -> (int) t * 2);
System.out.println(ArrayUtil.toString(result));
String[] keys = {"a", "bb", "ccc"};
Integer[] lengths = ArrayUtil.mapToArray(keys, String::length, Integer[]::new);
String[] keys = {"a", "bb", "ccc"};
List<Integer> lengths = ArrayUtil.mapToList(keys, String::length);
String[] keys = {"a", "bb", "c"};
Set<Integer> lengths = ArrayUtil.mapToSet(keys, String::length);
集合转数组
方法
说明
toArray(collection, componentType)
集合转数组。 注意:返回的 List 是固定大小数组列表 ,不能添加、移除元素。
List<String> list = List.of("a", "b");
String[] arr = ArrayUtil.toArray(list, String.class);
System.out.println("集合转数组:" + ArrayUtil.toString(arr));
5.3 字符串与输出
方法
说明
toString(array)
将数组转换为字符串。 自动识别原始类型和对象类型,避免打印出哈希码
join(array, conjunction)
使用指定分隔符将数组元素拼接为字符串
join(array, conjunction, prefix, suffix)
使用分隔符、前缀、后缀将数组元素拼接为字符串
join(array, conjunction, editor)
先对每个元素进行转换,再用分隔符拼接
int[] intArr = {1, 3, 56, 6, 7};
String[] strArr = {"aa", "bb", "cc"};
String str = ArrayUtil.toString(intArr);
System.out.println("将数组转换为字符串: " + str);
String result01 = ArrayUtil.join(intArr, ",");
System.out.println("使用指定分隔符将数组元素拼接为字符串: " + result01);
String result02 = ArrayUtil.join(strArr, ",", "[", "]");
System.out.println("使用分隔符、前缀、后缀将数组元素拼接为字符串: " + result02);
String result03 = ArrayUtil.join(strArr, " -> ", String::toUpperCase);
System.out.println("先对每个元素进行转换,再用分隔符拼接: " + result03);
六、其他常用方法
6.1 数组去重
方法
说明
distinct(array)
通过 equals 方法判断去重,生成新的数组,原数组不变
distinct(array, keyGenerator, override)
通过自定义 key 生成器去重。 override 为 true 时保留后面的值,为 false 时保留前面的值
String[] arr01 = {"aa", "bb", "cc", "dd", "bb", "dd"};
String[] result01 = ArrayUtil.distinct(arr01);
System.out.println("数组去重结果:" + ArrayUtil.toString(result01));
String[] arr02 = {"aa", "Aa", "BB", "bb"};
System.out.println("原数组:" + ArrayUtil.toString(arr02));
String[] r01 = ArrayUtil.distinct(arr02, String::toLowerCase, true);
System.out.println("忽略大小写去重,保留后面的值(覆盖模式):" + ArrayUtil.toString(r01));
String[] r02 = ArrayUtil.distinct(arr02, String::toLowerCase, false);
System.out.println("忽略大小写去重,保留前面的值(忽略模式):" + ArrayUtil.toString(r02));
6.2 合并与拆分
方法
说明
addAll(arrays)
将多个数组合并为一个数组,返回新数组,原数组不变
split(array, len)
将 byte 数组按指定长度平均拆分成多个子数组,常用于消息拆分
zip(keys, values, isOrder)
将两个数组(keys 和 values)按位置对应合并为 Map
String[] a = {"1", "2"};
String[] b = {"3", "4"};
String[] c = {"5", "6"};
String[] result = ArrayUtil.addAll(a, b, c);
System.out.println(ArrayUtil.toString(result));
byte[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
byte[][] result = ArrayUtil.split(arr, 3);
String[] keys = {"a", "b", "c"};
Integer[] values = {1, 2, 3};
Map<String, Integer> map = ArrayUtil.zip(keys, values, true);
6.3 克隆与复制
方法
说明
clone(array)
克隆数组,支持原始类型数组和对象数组。返回新数组,与原数组互不影响
copy(src, dest)
将源数组的元素复制到目标数组
copy(src, dest, length)
指定拷贝元素的个数
int[] a = {1, 2, 3};
int[] cloneA = ArrayUtil.clone(a);
Integer[] b = {1, 2, 3};
Integer[] cloneB = ArrayUtil.clone(b);
String[] src = {"a", "b", "c"};
String[] dest = new String[3];
ArrayUtil.copy(src, dest);
String[] src = {"a", "b", "c"};
String[] dest = new String[3];
ArrayUtil.copy(src, dest, 1);
6.4 最大值与最小值
方法
说明
max(array / values)
查找数组中的最大值。支持基本类型、对象数组,支持自定义比较器
min(array / values)
查找数组中的最小值。支持基本类型、对象数组,支持自定义比较器
System.out.println("查找数组中的最大值:" + ArrayUtil.max(1, 2, 13, 4, 5));
System.out.println("查找数组中的最小值:" + ArrayUtil.min(1, 2, 13, 4, 5));
Integer[] arr = {5, 2, 8, 1, 9};
System.out.println("查找数组中的最大值:" + ArrayUtil.max(arr));
System.out.println("查找数组中的最小值:" + ArrayUtil.min(arr));
BigDecimal[] nums = {new BigDecimal("2.0"), new BigDecimal("1.00"), new BigDecimal("3")};
BigDecimal minScale = ArrayUtil.min(nums, Comparator.comparingInt(BigDecimal::scale));
System.out.println("自定义比较器查找数组中的最小值:" + minScale);
BigDecimal maxScale = ArrayUtil.max(nums, Comparator.comparingInt(BigDecimal::scale));
System.out.println("自定义比较器查找数组中的最大值:" + maxScale);
6.5 数组排序
方法
说明
isSorted
检查数组是否有序
isSortedASC
检查数组是否升序
isSortedDESC
检查数组是否降序
6.6 数组反转
方法
说明
reverse(array)
反转数组,会变更原数组
shuffle(array)
打乱数组顺序,会变更原数组
swap(array, index1, index2)
交换数组中两个位置的值
int[] a = {1, 2, 3};
System.out.println("反转前的原数组:" + Arrays.toString(a));
ArrayUtil.reverse(a);
System.out.println("反转后的数组:" + Arrays.toString(a));
int[] b = {1, 2, 3};
System.out.println("打乱前的原数组:" + Arrays.toString(b));
ArrayUtil.shuffle(b);
System.out.println("打乱后的数组:" + Arrays.toString(b));
int[] c = {1, 2, 3};
System.out.println("交换前的原数组:" + Arrays.toString(c));
ArrayUtil.swap(c, 0, 2);
System.out.println("交换后的数组:" + Arrays.toString(c));
6.7 子数组
方法
说明
indexOfSub(array,subArray)
查找子数组在主数组中的位置
indexOfSub(array, beginInclude,subArray)
isSub(array, subArray)
判断是否为子数组
lastIndexOfSub
查找子数组在主数组中的最后位置
sub(array, start, end)
获取子数组,左闭右开,支持负数倒数
Integer[] a = {0, 1, 2, 3, 4};
Integer[] subResult = ArrayUtil.sub(a, 1, 3);
System.out.println("获取子数组,左闭右开:" + Arrays.toString(subResult));
七、总结
Hutool 不仅仅只有这一种工具类,还包含了其他许多工具类。在这里我作为一名Hutool的用户,我感谢Hutool的创作者和维护者们为我们带来如此强大便捷的工具库,希望Hutool功能越来越完善,为我们的开发工作带来更多的便利。同时也祝愿所有开发者没有BUG困扰,能够愉快地编写出高效、功能完善的程序。