arraylist下标越界异常本质是访问了0到size()-1范围外的索引,如空列表调用get(0)或对长度5的列表访问get(5);排查关键在于定位“谁在越界”和“为什么算错”,需检查堆栈首行、索引来源、size()值及高频风险场景如空集合未判、循环边界错误、多线程竞争等。

ArrayList 下标越界异常(IndexOutOfBoundsException)本质是访问了 0 到 size() - 1 范围之外的索引,比如对空列表调用 get(0),或对长度为 5 的列表访问 get(5)。排查关键不是掩盖异常,而是快速定位“谁在越界”和“为什么算错”。
看堆栈,锁定真实出错行
异常堆栈第一行(at xxx.xxx.Method(xxx.java:XX))就是实际抛出异常的位置。重点关注该行是否包含:
-
list.get(i)、list.set(i, x)或list.remove(i)等带索引的操作 - 索引变量是否来自外部输入(如 HTTP 参数、配置项、用户输入)
- 是否出现在循环体中,尤其是涉及
i+1、i-1偏移的相邻元素比较场景
验证三个关键值:长度、索引、来源逻辑
在报错行前加日志或打断点,确认:
-
list.size()—— 当前真实大小(注意:它可能为 0) - 待访问的索引值(如
i或idx)—— 打印出来看是不是负数、等于size()、或远大于预期 - 该索引怎么来的 —— 是循环变量?计算公式?还是从别处传入?例如:
int idx = (int) Math.floor(Math.random() * list.size())看似安全,但若list为空,size()为 0,乘法结果为 0,floor(0)还是 0,仍会越界
重点盯防高频出错场景
这些地方看似合理,却极易漏判:
-
空集合未检查:直接
list.get(0)或list.get(list.size() - 1),必须先if (list.isEmpty()) -
相邻元素比较写错循环条件:想比
i和i+1,却用for (int i = 0; i ,应改为 <code>i -
多线程共享 ArrayList:一个线程刚检查
list.size() > i,另一个线程立刻清空列表,再执行get(i)就越界;此时需换用Collections.synchronizedList或CopyOnWriteArrayList -
ParallelStream 意外修改:在并行流中对同一
ArrayList执行add或remove,可能破坏结构导致后续get越界
防御性写法,从源头堵住漏洞
不依赖“不会出错”的假设,而是主动控制边界:
- 对外部传入的索引,入口处校验:
if (idx = list.size()) throw new IllegalArgumentException(...) - JDK 9+ 可用
Objects.checkIndex(idx, list.size()),自动抛出带上下文信息的异常 - 遍历优先用增强 for 循环或迭代器,避开手动索引管理
- 需要下标又怕越界时,封装工具方法:
safeGet(list, idx, defaultValue),内部做判断后返回默认值











