1. 概述
在这个教程中,我们将讨论Java中的ArrayIndexOutOfBoundsException
。我们将理解它为什么会发生,并学习如何避免它。
2. ArrayIndexOutOfBoundsException
何时发生?
我们都知道,在Java中,数组是一种静态数据结构,我们在创建时就定义了其大小。我们通过索引访问数组的元素,数组的索引从0开始,且永远不能大于或等于数组的长度。
简单来说,**一般的规则是0 <= 索引 < (数组的大小)**。
当我们使用一个无效索引访问一个由数组支持的集合时,就会出现ArrayIndexOutOfBoundsException
。这意味着索引要么小于0,要么大于或等于数组的长度。
此外,边界检查在运行时进行。因此,ArrayIndexOutOfBoundsException
是一个运行时异常。所以,我们在访问数组的边界元素时需要格外小心。
让我们理解一些导致ArrayIndexOutOfBoundsException
的常见操作。
2.1. 访问数组
在访问数组时最常见的错误可能是忘记数组的上下界。
数组的下界始终为0,而上界则是其长度减1。
超出这些界限访问数组元素会导致ArrayIndexOutOfBoundsException
:
int[] numbers = new int[] {1, 2, 3, 4, 5};
int lastNumber = numbers[5];
这里,数组的大小为5,意味着索引范围从0到4。
在这种情况下,尝试访问第5个索引会引发ArrayIndexOutOfBoundsException
:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at ...
同样,如果我们向numbers
传递一个负数作为索引,也会得到ArrayIndexOutOfBoundsException
。
2.2. 访问Arrays.asList()
返回的List
静态方法Arrays.asList()
返回一个固定大小的列表,它由指定的数组支持。此外,它充当数组和基于集合API之间的桥梁。
这个返回的List
有一些根据索引访问其元素的方法。与数组类似,索引从0开始,直到其大小减1。
如果我们试图访问超出这个范围的Arrays.asList()
返回的List
的元素,会得到ArrayIndexOutOfBoundsException
:
List<Integer> numbersList = Arrays.asList(1, 2, 3, 4, 5);
int lastNumber = numbersList.get(5);
这里,我们再次尝试获取List
的最后一个元素。最后一个元素的位置是5,但其索引是4(大小减1)。因此,我们会得到ArrayIndexOutOfBoundsException
如下所示:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at java.base/java.util.Arrays$ArrayList.get(Arrays.java:4351)
at ...
同样,如果我们传递一个负索引,如-1,也会得到类似的结果。
2.3. 循环迭代
有时,在循环中遍历数组时,可能会设置错误的终止条件。
我们可能会结束迭代直到数组的长度,而不是长度减1:
int sum = 0;
for (int i = 0; i <= numbers.length; i++) {
sum += numbers[i];
}
在上述终止表达式中,循环变量i被比较为小于或等于现有数组numbers
的长度。所以在最后一次迭代中,i的值将变为5。
由于索引5超出了numbers
的范围,这将再次导致ArrayIndexOutOfBoundsException
:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at com.baeldung.concatenate.IndexOutOfBoundExceptionExamples.main(IndexOutOfBoundExceptionExamples.java:22)
3. 如何避免ArrayIndexOutOfBoundsException
?
现在,让我们了解一些避免ArrayIndexOutOfBoundsException
的方法。
3.1. 记住起始索引
我们必须始终记住,Java中的数组索引从0开始。 因此,第一个元素始终位于索引0,而最后一个元素位于数组长度减1的位置。
记住这个规则将帮助我们在大多数情况下避免ArrayIndexOutOfBoundsException
。
3.2. 正确使用循环中的运算符
如果错误地将循环变量初始化为索引1,可能会导致ArrayIndexOutOfBoundsException
。
同样,循环终止表达式中不正确使用 <
, <=
, >
, 或 >=
运算符也是这种异常发生的常见原因。
我们需要正确确定在循环中使用这些运算符的方式。
3.3. 使用增强for
循环
如果我们的应用程序运行在Java 1.5或更高版本,我们应该使用专门为遍历集合和数组设计的增强for
循环语句。它也使我们的循环更简洁、易于阅读。
此外,使用增强for
循环有助于完全避免ArrayIndexOutOfBoundsException
,因为它不涉及索引变量:
for (int number : numbers) {
sum += number;
}
在这里,我们不必担心索引。增强for
循环在每次迭代中都会取一个元素并将其分配给循环变量number
。因此,它完全避免了ArrayIndexOutOfBoundsException
。
4. IndexOutOfBoundsException
与ArrayIndexOutOfBoundsException
当尝试访问某种类型(如字符串、数组、List
等)的索引超出其范围时,会发生IndexOutOfBoundsException
。它是ArrayIndexOutOfBoundsException
和StringIndexOutOfBoundsException
的超类。
类似于ArrayIndexOutOfBoundsException
,当我们尝试使用超出字符串长度的索引访问字符串的字符时,也会抛出StringIndexOutOfBoundsException
。
5. 总结
在这篇文章中,我们探讨了ArrayIndexOutOfBoundsException
,它如何发生的一些示例,以及一些常见的避免方法。
一如既往,所有示例的源代码可以在GitHub上找到。