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. IndexOutOfBoundsExceptionArrayIndexOutOfBoundsException

当尝试访问某种类型(如字符串、数组、List等)的索引超出其范围时,会发生IndexOutOfBoundsException。它是ArrayIndexOutOfBoundsExceptionStringIndexOutOfBoundsException的超类。

类似于ArrayIndexOutOfBoundsException,当我们尝试使用超出字符串长度的索引访问字符串的字符时,也会抛出StringIndexOutOfBoundsException

5. 总结

在这篇文章中,我们探讨了ArrayIndexOutOfBoundsException,它如何发生的一些示例,以及一些常见的避免方法。

一如既往,所有示例的源代码可以在GitHub上找到。


« 上一篇: 自定义Zuul异常处理
» 下一篇: Java Weekly, 第424期