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

1. 前言

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

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

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

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

java 复制代码
public boolean findUser(String[] users, String targetUser) {
    if (users == null) {
        return false;
    }
    for (int i = 0; i < users.length; i++) {
        if (targetUser == null) {
            if (users[i] == null) {
                return true;
            }
        } else {
            if (targetUser.equals(users[i])) {
                return true;
            }
        }
    }
    return false;
}

public int findUserIndex(String[] users, String targetUser) {
    if (users == null) {
        return -1;
    }
    for (int i = 0; i < users.length; i++) {
        // ... 类似的重复代码
    }
    return -1;
}

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

2. 常用方法

2.1 包含检查方法

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

2.2 索引查找方法

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

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

java 复制代码
static int indexOf(Object[] array, Object objectToFind, int startIndex) {
    if (array == null) {
        return -1;
    } else {
        if (startIndex < 0) {
            startIndex = 0;
        }

        if (objectToFind == null) {
            for(int i = startIndex; i < array.length; ++i) {
                if (array[i] == null) {
                    return i;
                }
            }
        } else {
            for(int i = startIndex; i < array.length; ++i) {
                if (objectToFind.equals(array[i])) {
                    return i;
                }
            }
        }

        return -1;
    }
}

3. 与Stream API的对比

3.1 相同功能的不同实现

ArrayUtils方式:

java 复制代码
// 检查包含
boolean contains = ArrayUtils.contains(array, target);

// 查找索引
int index = ArrayUtils.indexOf(array, target);

Stream API方式:

java 复制代码
// 检查包含
boolean contains = Arrays.stream(array)
                        .anyMatch(element -> Objects.equals(element, target));

// 查找索引(较为繁琐)
int index = IntStream.range(0, array.length)
                    .filter(i -> Objects.equals(array[i], target))
                    .findFirst()
                    .orElse(-1);

3.2 性能对比

java 复制代码
public class PerformanceComparison {
    public static void main(String[] args) {
        String[] largeArray = createLargeArray(100000);
        
        // ArrayUtils性能测试
        long start1 = System.nanoTime();
        boolean result1 = ArrayUtils.contains(largeArray, "target");
        long time1 = System.nanoTime() - start1;
        
        // Stream API性能测试
        long start2 = System.nanoTime();
        boolean result2 = Arrays.stream(largeArray)
                               .anyMatch("target"::equals);
        long time2 = System.nanoTime() - start2;
        
        System.out.println("ArrayUtils耗时: " + time1 + "ns");
        System.out.println("Stream API耗时: " + time2 + "ns");
    }
}

3.3 适用场景分析

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

4. 总结

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

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

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

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

相关推荐
Fox爱分享14 分钟前
都问程序员双十一买什么,我的答案一定是这块专业编程显示器
后端·程序员·ai编程
小弥儿17 分钟前
38K星的开源项目 t3code:给 Claude Code 和 Codex 装一个手机遥控器
学习·智能手机·开源·github
分布式存储与RustFS20 分钟前
可观测性数据落进对象存储:Proscia 案例拆解与 ClickHouse 自托管配置
运维·云原生·开源·对象存储·分布式存储·s3·性能基准
SL_staff21 分钟前
制造订单交付闭环实践:用跨部门计划模板解决缺料-停机-返工三角死循环
java·开源·产品
CCblandy27 分钟前
缓存淘汰实测:一次全表扫描把 LRU 命中率从 46% 打到 38%,W-TinyLFU 守住 50% 却贵 11 倍
后端·python·缓存·性能优化·架构
武子康37 分钟前
DOA 100%、GSC 改善 12 dB,ESP32-P4 远场拾音就能用了吗?
人工智能·后端·agent
日日大王学编程1 小时前
deerflow-memory-design-blog
python·langchain·开源
愚农搬码1 小时前
企业为什么需要表单引擎,而不是继续手写 Vue 表单?
后端
孟陬1 小时前
技术周刊#158:ChatGPT 智能 UI 底层原理、个人智能体协议正式发布、一条 POST 请求即可锁死 Next.js 服务
人工智能·后端·全栈
miofly2 小时前
MIT 团队用 GPT-6 Astra 改写小模型权重,跳过梯度训练提升指令遵循能力
开源·github