ArrayList 的 IndexOutOfBoundsException 源于访问非法索引,即负数或 ≥ size() 的下标;需通过异常堆栈定位具体代码行,检查循环边界、添加预校验或封装安全方法,并用单元测试覆盖空列表、size=1及越界场景。

Java 中 ArrayList 的 IndexOutOfBoundsException 通常发生在访问不存在的索引位置时,比如用 get(i)、set(i, e)、remove(i) 等方法时传入了负数或 ≥ size() 的下标。排查重点不是“为什么报错”,而是“谁在什么时候用了什么下标”。
确认异常堆栈里具体是哪一行触发的
先看控制台打印的完整异常信息,重点关注:
- 异常类型和消息(例如:
Index: 5, Size: 5表示你试图访问索引 5,但集合最大合法索引是 4) - 堆栈最顶端的代码行(通常是你的业务代码,比如
list.get(i)那一行) - 如果用了循环,检查循环变量是否越界(常见于
for (int i = 0; i —— 这里用了 <code> 而不是 <code>)
检查所有涉及下标的 ArrayList 操作
逐行审查代码中所有显式使用下标的调用,包括:
-
list.get(i):确保i >= 0 && i -
list.set(i, e):同上,且不能对空列表设索引 0 -
list.remove(i):同样要求索引合法;注意移除后后续元素前移,若在循环中边遍历边删除,容易导致跳过元素或二次越界 -
list.add(i, e):允许i == list.size()(插到最后),但不允许i > list.size()或负数
留意并发修改或动态变化的 size
如果多个线程共享同一个 ArrayList,或者在循环过程中 size 被其他逻辑改变(比如监听器回调、异步任务),可能导致判断 i 时成立,但真正执行 <code>get(i) 时 size 已变小。解决方式:
立即学习“Java免费学习笔记(深入)”;
- 单线程场景:加日志或断点,观察
list.size()和i在出错前一刻的真实值 - 多线程场景:改用线程安全容器(如
CopyOnWriteArrayList),或加同步块保护读写 - 循环中修改:避免用普通 for 循环正向遍历并
remove;改用迭代器remove(),或倒序 for 循环
用防御性编程提前拦截
不依赖运行时报错来发现问题,主动加校验:
- 在调用
get(i)前加断言:if (i = list.size()) throw new IllegalArgumentException("Invalid index: " + i); - 封装工具方法,统一处理边界:
safeGet(list, i, defaultValue) - 单元测试覆盖边界用例:空列表、size=1、取 index=-1 / size / size+1
注意:ArrayList 的合法索引范围永远是 [0, size() - 1],没有“第 size() 个元素”这种说法——那是插入位置,不是访问位置。


















