跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
JavaAIjava算法

慎用 ArrayList 的 contains 方法,优先使用 HashSet

在排查应用启动缓慢时,真正的瓶颈并不在数据库读取,而是在去重逻辑中反复调用 ArrayList.contains()。由于该方法底层是线性遍历,6 万条数据在高频查找下会产生明显性能开销。将用于判断重复的容器改为 HashSet 后,查找复杂度大幅下降,去重耗时从数分钟缩短到约 1 秒,适合用 Set 替代 List 处理高频存在性判断。

DebugKing发布于 2015/10/20更新于 2026/9/741 浏览
慎用 ArrayList 的 contains 方法,优先使用 HashSet

问题背景

在排查一个应用启动缓慢的问题时,我先怀疑是要加载的数据量太大。可实际看了下数据库,只有 6 万条左右。更奇怪的是,单独写一个读取这 6 万条数据的方法,跑完竟然不到 10 秒。说明瓶颈不在数据库,而是在后面的处理逻辑里。

继续往下看,问题出在一段去重代码上:系统会把记录里某几个字段拼成一个唯一键,如果这个键已经出现过,就认为这条数据是重复的,直接跳过。实现方式很直白:先用一个 List 存这些唯一键,再通过 contains 判断是否已经存在。

List<String> uniqueKeyList = new ArrayList<String>();
// ...
if (uniqueKeyList.contains(uniqueKey)) {
    continue;
}

为什么会慢

ArrayList.contains() 的底层并不是'快速查找',它最终会走到 indexOf(),本质上就是一次线性遍历:

public int indexOf(Object elem) {
    if (elem == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i] == null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (elem.equals(elementData[i]))
                return i;
    }
    return -1;
}

这意味着,列表越长,contains() 越慢。这里有 6 万条数据,去重过程中每次都要扫一遍 List,累计下来就是很可观的时间开销。启动阶段又特别敏感,几秒钟都可能被放大成明显的卡顿。

改成 HashSet 之后

这类'判断是否已存在'的场景,更合适的容器其实是 Set。把原来的 List 换成 HashSet 后,代码结构几乎不需要大改:

Set<String> uniqueKeySet =  <String>();

 (uniqueKeySet.contains(uniqueKey)) {
    ;
}
new
HashSet
// ...
if
continue

HashSet.contains() 的实现依赖底层的哈希表结构,查找时不需要像 ArrayList 那样从头扫到尾,所以在大数据量下性能差异会非常明显。这里的去重耗时也从原来的数分钟,直接降到了 1 秒左右。

public boolean contains(Object o) {
    return map.containsKey(o);
}

结论

如果你的场景是'判断元素是否存在',而且数据量不小、查找频率又高,ArrayList.contains() 往往不是合适的选择。它适合顺序访问、遍历处理,但不适合高频 membership check。

这类场景下,优先考虑 HashSet,通常能用很小的代码改动换来很明显的性能收益。

目录

  1. 问题背景
  2. 为什么会慢
  3. 改成 HashSet 之后
  4. 结论

更多推荐文章

查看全部
  • 分布式文件系统 HDFS:常用命令、Web 页面与 Java API 编程实践
  • 智能仿真无人机平台多线程实现:任务分配与碰撞规避
  • Java API 实战:从基础爬虫构建到条件数据提取,详解 URL 与正则策略
  • 4GB 显存限制下构建 LLM 基础开发环境指南
  • IQuest-Coder-V1 与 Meta-Llama-Code 开源模型部署对比
  • ComfyUI 是什么?节点式 AI 绘画工作流详解
  • 项目经理指南:嵌入、Copilot 与 AI Agent 模式场景解析及 LLM 策略选择
  • 具身智能深度解析:深度视觉如何赋予足式机器人跑酷能力
  • FPGA 基础面试题详解:架构、时序与跨时钟域
  • 从零开始搭建 Trae 的 Java 开发环境
  • 2026 前端跨端框架选型指南
  • 基于 YOLOv26 的无人机遥感环境监测系统
  • 前端权限管理实战:如何优雅地控制用户视图
  • Coze 平台 AI 智能体零基础使用教程
  • OpenAkita:自我进化的开源 AI 助手框架
  • 使用 TRAE CN 与 MasterGo MCP 将设计稿转化为前端代码
  • Flutter 集成 BIP340 实现鸿蒙 Schnorr 签名实战
  • 物理信息神经网络(PINN):AI 与物理定律的融合新范式
  • 动态规划:最长公共子序列(LeetCode-1143)
  • Python 真随机数生成与安全实践指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online