
为什么 ArrayIndexOutOfBoundsException 总在运行时才报?
Java 不做编译期下标合法性检查,只靠运行时数组访问触发边界校验。这意味着写 arr[10] 时如果 arr.length == 5,编译完全通过,但一执行就崩——不是语法错,是逻辑错。
常见错误现象:
- 循环变量多加/少减 1(比如用
替代 <code>) - 空数组未判空直接取
arr[0] - 从外部输入(如命令行、文件)读索引,没做范围过滤
- 多线程共享数组,一个线程扩容、另一个还在用旧长度遍历
怎么安全地访问数组元素?
别依赖“我写的循环肯定没错”,而是把边界检查变成显式逻辑。尤其在索引来自计算、用户或状态变化时。
- 访问前先判断:
if (i >= 0 && i - 用增强 for 循环替代手动索引(当不需要下标本身时):
for (int x : arr) { ... } - 对可能为空的数组,统一用
Objects.requireNonNull(arr, "arr must not be null")或提前 return - 工具类封装常用操作,比如
ArrayUtils.get(array, index, defaultValue)(Apache Commons)
哪些场景最容易漏掉边界检查?
不是所有数组访问都危险,但以下几类特别容易栽:
立即学习“Java免费学习笔记(深入)”;
-
String.charAt(i):字符串本质是 char 数组,i超出str.length()就抛StringIndexOutOfBoundsException(它继承自ArrayIndexOutOfBoundsException) - 二维数组嵌套访问:
matrix[i][j]要分别检查i 和 <code>j ,后者常被忽略 - 使用
Arrays.copyOfRange()时传入非法from/to:比如from = 3, to = 1或to > array.length - 流式处理转回数组:
list.toArray(new String[list.size()])如果 list 是空,new 出的数组长度为 0,后续任何索引访问都越界
调试时怎么快速定位越界位置?
堆栈里只显示异常抛出处,但真正的问题往往在上游——比如索引值是上一步算错的。
- 在抛异常的行前后加日志:
System.out.println("i=" + i + ", arr.length=" + arr.length); - 用 IDE 调试器停在异常行,看变量值;注意检查「计算索引的表达式」,比如
index = list.size() - 1在 list 为空时就是 -1 - 启用 JVM 参数
-XX:+PrintGCDetails没用,但-ea(启用断言)可辅助验证:assert i >= 0 && i - 静态分析工具如 SpotBugs 能检出部分明显越界模式,但对动态计算索引无能为力
越界问题从来不在那一行代码本身,而在你对数据状态的假设和实际不一致。最麻烦的是那种“大部分时间正常,偶尔崩”的情况——说明边界条件只在特定输入路径下暴露,得顺着数据流往回追三步。










