什么导致java.lang.ArrayIndexOutOfBoundsException,我该如何防止它?

ArrayIndexOutOfBoundsException是什么意思,我该如何摆脱它?

以下是触发exception的代码示例:

 String[] name = {"tom", "dick", "harry"}; for(int i = 0; i<=name.length; i++) { System.out.print(name[i] +'\n'); } 

你的第一个停靠港应该是合理清楚地解释它的文件 :

抛出以指示已经使用非法索引访问数组。 该索引是否定的或者大于或等于数组的大小。

举个例子:

 int[] array = new int[5]; int boom = array[10]; // Throws the exception 

至于如何避免呢…呃,不要这样做。 小心你的数组索引。

人们偶然遇到的一个问题是认为数组是1索引的,例如

 int[] array = new int[5]; // ... populate the array here ... for (int index = 1; index <= array.length; index++) { System.out.println(array[index]); } 

这将错过第一个元素(索引0),并在索引为5时抛出一个exception。这里的有效索引是0-4(含)。 这里的正确,惯用for陈述是:

 for (int index = 0; index < array.length; index++) 

(当然假设你需要索引,如果你可以使用增强的for循环,那就这样做。)

 if (index < 0 || index >= array.length) { // Don't use this index. This is out of bounds (borders, limits, whatever). } else { // Yes, you can safely use this index. The index is present in the array. Object element = array[index]; } 

也可以看看:

  • Java教程 – 语言基础 – 数组

更新 :根据你的代码片段,

 for(int i = 0; i<=name.length; i++) { 

索引包含数组的长度。 这是超出界限的。 你需要用<=replace<=

 for(int i = 0; i < name.length; i++) { 

简要说一下:

在最后一次迭代中

 for(int i = 0; i<=name.length; i++) { 

i将等于name.length这是一个非法的指数,因为数组索引是从零开始的。

你的代码应该阅读

 for(int i = 0; i < name.length; i++) ^ 

这意味着你正试图访问一个数组的索引,因为它不在边界之间。

例如,这将初始化一个上限为4的原始整型数组。

 int intArray[] = new int[5]; 

程序员从零开始计数。 所以这个例子会抛出一个ArrayIndexOutOfBoundsException因为上限是4而不是5。

 intArray[5]; 

为了避免数组索引超出范围的exception,应该在何时何地可以使用enhanced- for语句。

主要动机(和用例)是在迭代时,不需要任何复杂的迭代步骤。 您将无法使用增强型在数组中向后移动或仅在每个其他元素上迭代。

这样做可以保证不会耗尽元素,并且可以轻松地转换您的[更正后的]示例。

下面的代码:

 String[] name = {"tom", "dick", "harry"}; for(int i = 0; i< name.length; i++) { System.out.print(name[i] + "\n"); } 

相当于这个:

 String[] name = {"tom", "dick", "harry"}; for(String firstName : name) { System.out.println(firstName + "\n"); } 

什么导致ArrayIndexOutOfBoundsException

如果你把一个variables想象成一个可以放置一个值的“盒子”,那么一个数组就是一系列放在彼此旁边的盒子,盒子的数量是一个有限的显式整数。

像这样创build一个数组:

 final int[] myArray = new int[5] 

创build一行5个框,每个框持有一个int 。 每个方框都有一个索引,一系列方框中的一个位置。 该索引从0开始,并在N-1结束,其中N是数组的大小(框的数量)。

要从这一系列框中检索其中一个值,可以通过索引来引用它,如下所示:

 myArray[3] 

这将给你的系列中的第四个框的值(因为第一个框的索引为0)。

ArrayIndexOutOfBoundsException是由于尝试通过传递比最后一个“box”的索引更高的索引或负数来检索不存在的“框”而引起的。

以我的运行示例,这些代码片段会产生这样一个例外:

 myArray[5] //tries to retrieve the 6th "box" when there is only 5 myArray[-1] //just makes no sense myArray[1337] //waay to high 

如何避免ArrayIndexOutOfBoundsException

为了防止ArrayIndexOutOfBoundsException ,需要考虑一些关键点:

循环

在循环数组时,请确保您检索的索引严格小于数组的长度(框的数量)。 例如:

 for (int i = 0; i < myArray.length; i++) { 

注意< ,从来没有在那里混合a = ..

你可能想要做这样的事情:

 for (int i = 1; i <= myArray.length; i++) { final int someint = myArray[i - 1] 

只是不要。 坚持上面的(如果你需要使用索引),它会为您节省很多的痛苦。

在可能的情况下,使用foreach:

 for (int value : myArray) { 

这样你就不必考虑索引了。

循环时,不pipe你做什么,都不要改变循环迭代器的值(这里是: i )。 这应该改变价值的唯一的地方是保持循环。 否则改变它只是冒着一个例外,而且在大多数情况下是不必要的。

检索/更新

当检索数组中的一个任意元素时,总是检查它是否是一个对数组长度有效的索引:

 public Integer getArrayElement(final int index) { if (index < 0 || index >= myArray.length) { return null; //although I would much prefer an actual exception being thrown when this happens. } return myArray[index]; } 

在你的代码中,你已经访问了从索引0到string数组长度的元素。 name.length给出了string对象数组中的string对象的数量,即3,但是只能访问到索引2的name[2] ,因为数组可以从索引0访问到name.length - 1name.length对象的数量。

即使在使用for循环的时候,你已经开始使用索引零,你应该以name.length - 1结束。 在数组a [n]中,您可以访问从[0]到[n-1]的格式。

例如:

 String[] a={"str1", "str2", str3" ..., "strn"}; for(int i=0;i<a.length()i++) System.out.println(a[i]); 

在你的情况下:

 String[] name = {"tom", "dick", "harry"}; for(int i = 0; i<=name.length; i++) { System.out.print(name[i] +'\n'); } 

对于这个简单的问题,这么多,但我只是想强调一个Java中的新function,这将避免所有在数组中的索引混淆,即使是初学者。 Java-8抽象了为你迭代的任务。

 int[] array = new int[5]; //If you need just the items Arrays.stream(array).forEach(item -> { println(item); }); //If you need the index as well IntStream.range(0, array.length).forEach(index -> { println(array[index]); }) 

有什么好处? 那么,一件事是像英文的可读性。 其次,您不必担心ArrayIndexOutOfBoundsException

我所见过的看起来很神秘的ArrayIndexOutOfBoundsExceptions(即显然不是由您自己的数组处理代码引起的)最常见的情况是SimpleDateFormat的并发使用。 特别是在一个servlet或控制器

 public class MyController { SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy"); public void handleRequest(ServletRequest req, ServletResponse res) { Date date = dateFormat.parse(req.getParameter("date")); } } 

如果两个线程一起inputSimplateDateFormat.parse()方法,您可能会看到ArrayIndexOutOfBoundsException。 请注意SimpleDateFormat的类javadoc的同步部分。

确保在你的代码中没有任何地方是像servlet或控制器那样以并发的方式访问像SimpleDateFormat这样的线程不安全的类。 检查您的servlets程序和控制器的所有实例variables可能的嫌疑人。

对于任何长度为n的数组,数组的元素将具有从0到n-1的索引。

如果你的程序试图访问数组索引大于n-1的任何元素(或内存),那么java将抛出ArrayIndexOutOfBoundsException

所以这里有两个解决scheme,我们可以在程序中使用

1.保持计数:

 for(int count = 0; count < array.length; count++) { System.out.println(array[count]); } 

或者像其他一些循环语句

 int count = 0; while(count < array.length) { System.out.println(array[count]); count++; } 

2.使用For Each循环的方法,在这个方法中,程序员不需要为数组中元素的数量而烦恼。

 for(String str : array) { System.out.println(str); } 

由于i<=name.length部分,您将获得ArrayIndexOutOfBoundsExceptionname.length返回stringname的长度,即3。因此当你试图访问name[3] ,它的非法并抛出exception。

解决的代码:

 String[] name = {"tom", "dick", "harry"}; for(int i = 0; i < name.length; i++) { //use < insteadof <= System.out.print(name[i] +'\n'); } 

它在Java语言规范中定义:

public final字段length ,其中包含数组的组件数。 length可能是正数或零。

数组索引越界异常

这就是这种types的exception在Eclipse中抛出时的样子; 红色的数字表示您尝试访问的索引。 所以代码看起来像这样:

 myArray[5] 

当您尝试访问该数组中不存在的索引时,会引发该错误。 如果一个数组的长度为3:

 int[] intArray = new int[3]; 

那么唯一有效的指标是:

 intArray[0] intArray[1] intArray[2] 

如果一个数组的长度为1:

 int[] intArray = new int[1]; 

那么唯一有效的指标是:

 intArray[0] 

任何等于数组长度的整数或大于它的整数:超出范围。 任何小于0的整数都是越界的;

PS如果你对数组有更好的理解并做一些实际的练习,这里有一个video: 关于java中数组的教程

您不能迭代或存储比数组长度更多的数据。 在这种情况下,你可以这样做:

 for (int i = 0; i <= name.length - 1; i++) { // .... } 

或这个:

 for (int i = 0; i < name.length; i++) { // ... }