ArrayUtils:Java数组操作的瑞士军刀

作者:白衣鸽子日期:2025/11/16

1. 前言

本文介绍的 ArrayUtils 以org.apache.commons.collections4.ArrayUtils 为例

源代码:org.apache.commons.collections4.ArrayUtils

自定义特征可以在自己服务内实现

在Java应用开发中,数组操作是我们日常编码的基础任务之一。你是否曾写过下面这样的代码?

1public boolean findUser(String[] users, String targetUser) {
2    if (users == null) {
3        return false;
4    }
5    for (int i = 0; i < users.length; i++) {
6        if (targetUser == null) {
7            if (users[i] == null) {
8                return true;
9            }
10        } else {
11            if (targetUser.equals(users[i])) {
12                return true;
13            }
14        }
15    }
16    return false;
17}
18
19public int findUserIndex(String[] users, String targetUser) {
20    if (users == null) {
21        return -1;
22    }
23    for (int i = 0; i < users.length; i++) {
24        // ... 类似的重复代码
25    }
26    return -1;
27}
28

这种手动遍历数组的方式不仅繁琐、重复,更重要的是需要处理各种边界情况(如空数组、null元素、起始位置等),容易出错且代码可读性差。一个精心设计的工具类可以封装这些通用逻辑,让数组操作变得简单而安全。本文将深入解析ArrayUtils工具类的实现原理,展示如何通过简洁的API解决数组操作的常见痛点。

2. 常用方法

2.1 包含检查方法

2.1.1 方法签名
1static boolean contains(Object[] array, Object objectToFind)
2
2.1.2 应用示范
1public class ArrayUtilsDemo {
2    public static void main(String[] args) {
3        String[] fruits = {"apple", "banana", "orange", null};
4        
5        // 检查元素是否存在
6        System.out.println(ArrayUtils.contains(fruits, "apple")); // true
7        System.out.println(ArrayUtils.contains(fruits, "grape")); // false
8        System.out.println(ArrayUtils.contains(fruits, null));    // true
9        
10        // 处理空数组场景
11        String[] emptyArray = null;
12        System.out.println(ArrayUtils.contains(emptyArray, "test")); // false
13    }
14}
15
2.1.3 关键源码
1static boolean contains(Object[] array, Object objectToFind) {
2    return indexOf(array, objectToFind) != -1;
3}
4

2.2 索引查找方法

2.2.1 方法签名
1static <T> int indexOf(T[] array, Object objectToFind)
2static int indexOf(Object[] array, Object objectToFind, int startIndex)
3
2.2.2 应用示范
1public class IndexOfDemo {
2    public static void main(String[] args) {
3        Integer[] numbers = {1, 2, 3, 2, 5, null, 2};
4        
5        // 查找元素首次出现位置
6        System.out.println(ArrayUtils.indexOf(numbers, 2));     // 1
7        System.out.println(ArrayUtils.indexOf(numbers, 10));    // -1
8        System.out.println(ArrayUtils.indexOf(numbers, null));  // 5
9        
10        // 从指定位置开始查找
11        System.out.println(ArrayUtils.indexOf(numbers, 2, 2));  // 3
12        System.out.println(ArrayUtils.indexOf(numbers, 2, 4));  // 6
13        
14        // 处理边界情况
15        System.out.println(ArrayUtils.indexOf(null, 1));        // -1
16    }
17}
18
2.2.3 关键源码

本质比较的是equals方法,如有需要可以重写equals方法

1static int indexOf(Object[] array, Object objectToFind, int startIndex) {
2    if (array == null) {
3        return -1;
4    } else {
5        if (startIndex < 0) {
6            startIndex = 0;
7        }
8
9        if (objectToFind == null) {
10            for(int i = startIndex; i < array.length; ++i) {
11                if (array[i] == null) {
12                    return i;
13                }
14            }
15        } else {
16            for(int i = startIndex; i < array.length; ++i) {
17                if (objectToFind.equals(array[i])) {
18                    return i;
19                }
20            }
21        }
22
23        return -1;
24    }
25}
26

3. 与Stream API的对比

3.1 相同功能的不同实现

ArrayUtils方式:

1// 检查包含
2boolean contains = ArrayUtils.contains(array, target);
3
4// 查找索引
5int index = ArrayUtils.indexOf(array, target);
6

Stream API方式:

1// 检查包含
2boolean contains = Arrays.stream(array)
3                        .anyMatch(element -> Objects.equals(element, target));
4
5// 查找索引(较为繁琐)
6int index = IntStream.range(0, array.length)
7                    .filter(i -> Objects.equals(array[i], target))
8                    .findFirst()
9                    .orElse(-1);
10

3.2 性能对比

1public class PerformanceComparison {
2    public static void main(String[] args) {
3        String[] largeArray = createLargeArray(100000);
4        
5        // ArrayUtils性能测试
6        long start1 = System.nanoTime();
7        boolean result1 = ArrayUtils.contains(largeArray, "target");
8        long time1 = System.nanoTime() - start1;
9        
10        // Stream API性能测试
11        long start2 = System.nanoTime();
12        boolean result2 = Arrays.stream(largeArray)
13                               .anyMatch("target"::equals);
14        long time2 = System.nanoTime() - start2;
15        
16        System.out.println("ArrayUtils耗时: " + time1 + "ns");
17        System.out.println("Stream API耗时: " + time2 + "ns");
18    }
19}
20

3.3 适用场景分析

特性ArrayUtilsStream API
代码简洁性⭐⭐⭐⭐⭐⭐⭐⭐
性能⭐⭐⭐⭐⭐⭐⭐⭐
可读性⭐⭐⭐⭐⭐⭐⭐⭐⭐
函数式支持⭐⭐⭐⭐⭐⭐⭐
链式操作不支持支持
空安全⭐⭐⭐⭐⭐需要额外处理

4. 总结

ArrayUtils通过简洁的API设计,为我们提供了强大的数组操作能力。它的主要优势包括:

  1. 代码简洁性:将常见的数组操作封装成简单的方法调用
  2. 空安全:妥善处理null值场景,提高代码健壮性
  3. 灵活性:支持从指定位置开始搜索,满足不同业务需求
  4. 类型安全:使用泛型确保类型一致性

虽然这个工具类功能相对基础,但它体现了良好的设计思想:专注于解决特定问题,保持接口简单,处理边界情况。在实际开发中,我们可以借鉴这种设计思路,创建更多实用的工具类来提升开发效率。

建议使用场景:适合中小型数组的快速操作,对于性能要求极高的场景建议考虑其他优化方案。


ArrayUtils:Java数组操作的瑞士军刀》 是转载文章,点击查看原文


相关推荐


一文搞懂 AI 流式响应
只想写个小玩意2025/11/15

这是 OpenAI 文档中流式响应的代码 platform.openai.com/docs/guides… import { OpenAI } from "openai"; const client = new OpenAI(); const stream = await client.responses.create({ model: "gpt-5", input: [ { role: "user", conte


TRAE SOLO推出1天啦,限免到15号,你还没体验吗
也无风雨也雾晴2025/11/13

Trae SOLO模式已经正式推出一天了 点击左上角的logo,就可以切换solo模式了,切换后的ide布局非常的酷炫,有两个模式 coder:可以用来改bug,写需求这些 builder:适合从0到1的开发,从生成prd开始到构建完整项目,而且trae还提供了便捷部署到vercel可以线上访问的集成 但是没有模型相关的选择,内置进去了,没有暴露出来给用户去选择 我试了一下使用coder改bug,plan模式下提出需求或者bug,会先生成文档,你可以根据文档再次确认需求,没问题后开始实施,这


一文看懂 Agentic AI:搭建单体 vs 多智能体系统,结果出乎意料!
玩转AGI2025/11/12

一文看懂 Agentic AI:搭建单体 vs 多智能体系统,结果出乎意料! 最近,我开始尝试构建不同类型的 Agentic AI 系统,最让我着迷的,是“单智能体(Single-Agent)”和“多智能体(Multi-Agent)”的差异。【AI大模型教程】 说实话,在没真正动手之前,我也只是听过这些概念,觉得听起来很玄。直到我用 LangGraph 和 LangSmith Studio 亲自搭建了两个版本,一个“单兵作战”,一个“多智能体协作”,结果真的让我彻底改观。 我想造一个能帮我追踪


Guava 迭代器增强类介绍
桦说编程2025/11/10

Guava 库为 Java 开发者提供了一系列强大的迭代器增强工具,它们简化了复杂迭代模式的实现。本文将深入探讨 Guava 的 PeekingIterator、AbstractIterator 和 AbstractSequentialIterator。 1. PeekingIterator:洞察先机 标准的 Iterator 接口仅提供 hasNext() 和 next() 方法,这在某些场景下显得力不从心。当需要“预读”下一个元素以做出决策,但又不想立即消耗它时,PeekingIterato


🍎 Electron 桌面端应用合法性问题全流程解决指南(新手友好版)
去码头整点薯片2025/11/8

本文目标:帮助你把本地的 Electron 应用打包成 macOS 的 .dmg,并做到打开不再被 Gatekeeper 拦截(不再提示“来自身份不明的开发者/无法验证是否含有恶意软件”)。 适用对象:个人开发者 & 小团队。 🧩 一、问题场景 当你满心欢喜地将精心开发的 Electron 应用打包分发给用户,却接到反馈:在 macOS 上无法打开,系统弹窗冷冰冰地提示“无法验证开发者”,文件被直接移入废纸篓。 如果这个场景让你感同身受,那么你正遭遇 macOS 强大的 Gatekeepe


Python 的内置函数 globals
IMPYLH2025/11/6

Python 内建函数列表 > Python 的内置函数 globals Python 的内置函数 globals() 是一个非常重要的工具函数,它返回一个字典,表示当前全局符号表。这个字典包含了当前模块中定义的所有全局变量、函数和类的名称及其对应的值。 def globals(): ''' 返回实现当前模块命名空间的字典 :return: 当前模块命名空间的字典 ''' 具体来说: 返回值是一个字典对象字典的键是变量名或函数名(字符串形式)字典的值是


Python 的内置函数 filter
IMPYLH2025/11/1

Python 内建函数列表 > Python 的内置函数 eval Python 的内建函数 filter() 是一个非常有用的高阶函数,它用于对可迭代对象进行筛选过滤。它的基本工作原理是根据指定的函数条件,从输入的可迭代对象中筛选出符合条件的元素,返回一个迭代器对象。 def filter(fn, iterable): ''' 过滤数据 :param fn: 回调函数,返回 True 是元素保留,返回 False 时元素去除 :param iterable


彻底搞懂「字幕」:从格式、软硬到嵌入,告别所有困惑
mortimer2025/10/30

“我明明把字幕加上了,为什么播放时看不到?” “为什么别人的视频能切换中英文字幕,我的就不行?” “软字幕、硬字幕、.srt、.ass……这些到底是什么鬼?” 如果你曾被这些问题困扰,那么这篇文章就是为你准备的。我将用最清晰的逻辑和最易懂的语言,一次性讲透关于字幕的所有核心知识。 第一站:先懂最核心的区别 —— 软字幕 vs. 硬字幕 在讨论任何格式或工具之前,你必须先理解字幕最终呈现的两种形态。这决定了你的字幕能否被关闭或切换。 硬字幕 (Hard Subs):印在画面上的“纹身” 硬字幕


Redis(87)Redis缓存的LRU淘汰策略如何配置?
Victor3562025/10/27

配置Redis缓存的LRU(Least Recently Used,最近最少使用)淘汰策略需要以下几个步骤: 设置最大内存限制 选择和配置淘汰策略 验证配置 以下是详细的步骤和代码示例。 1. 设置最大内存限制 可以在Redis配置文件 redis.conf 中设置 maxmemory 选项来限制Redis使用的最大内存。 # redis.conf # 设置最大内存为256MB maxmemory 256mb 如果你不使用配置文件,可以通过命令行参数直接设置: redis-server -


Redis(80)如何解决Redis的缓存穿透问题?
Victor3562025/10/24

解决Redis缓存穿透问题的方法有多种,具体的解决方案可以根据实际情况选择。以下是几种常见的解决方法及详细的代码示例,包括缓存空结果、使用布隆过滤器以及参数校验。 1. 缓存空结果 当查询数据库返回空结果时,也将其缓存起来,并设置一个较短的过期时间,比如5分钟。这样即使请求数据不存在,也不需要每次都访问数据库。 示例代码: import redis.clients.jedis.Jedis; import com.fasterxml.jackson.databind.ObjectMapper;

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0