关于数组:导致java.lang.ArrayIndexOutOfBoundsException的原因是什么以及如何阻止它?

What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?

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

下面是触发异常的代码示例:

1
2
3
4
String[] name = {"tom","dick","harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}


您的第一个停靠港应该是能够合理清晰地解释这一点的文档:

Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.

例如:

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

至于如何避免它…嗯,别这样。小心数组索引。

人们有时会遇到的一个问题是认为数组是单索引的,例如

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

这将遗漏第一个元素(索引0),并在索引为5时引发异常。这里的有效索引包括0-4。这里的正确、惯用的for声明是:

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

(当然,这是假设你需要索引。如果您可以使用增强的for循环,请执行此操作。)


1
2
3
4
5
6
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教程-语言基础-数组

更新:根据代码片段,

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

索引包含数组的长度。这是越界的。你需要用<替换<=

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

简而言之:

在的最后一个迭代中

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

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

你的代码应该是

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


这意味着您正试图访问数组的索引,该索引无效,因为它不在边界之间。

例如,这将初始化一个上界为4的基元整数数组。

1
int intArray[] = new int[5];

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

1
intArray[5];


为了避免数组索引越界异常,应该在可能的位置和时间使用增强型-for语句。

主要的动机(和用例)是当您在迭代时,您不需要任何复杂的迭代步骤。您将无法使用增强的-for在数组中向后移动,或者只能迭代其他元素。

在执行此操作时,保证不会耗尽要迭代的元素,并且您的[corrected]示例很容易转换。

代码如下:

1
2
3
4
5
String[] name = {"tom","dick","harry"};
for(int i = 0; i< name.length; i++) {
    System.out.print(name[i] +"
"
);
}

…相当于:

1
2
3
4
5
String[] name = {"tom","dick","harry"};
for(String firstName : name) {
    System.out.println(firstName +"
"
);
}


是什么导致了ArrayIndexOutOfBoundsException

如果你把一个变量看作是一个"框",你可以在其中放置一个值,那么数组就是一系列放置在每个框旁边的框,框的数量是一个有限的显式整数。

创建这样的数组:

1
final int[] myArray = new int[5]

创建一行5个框,每个框包含一个int。每个框都有一个索引,一个在一系列框中的位置。这个索引从0开始,到n-1结束,其中n是数组的大小(框的数量)。

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

1
myArray[3]

它将为您提供系列中第4个框的值(因为第一个框的索引为0)。

ArrayIndexOutOfBoundsException是由于试图检索不存在的"box",通过传递一个高于最后一个"box"的索引或负的索引而引起的。

在我的运行示例中,这些代码片段将产生这样一个异常:

1
2
3
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,需要考虑以下几个关键点:

循环

循环遍历数组时,始终确保要检索的索引严格小于数组的长度(框数)。例如:

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

注意<,不要在里面混用=

你可能想做这样的事情:

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

不要这样做。坚持上面的那个(如果你需要使用索引的话),它会让你省去很多痛苦。

如有可能,使用foreach:

1
for (int value : myArray) {

这样就不必考虑索引了。

循环时,无论您做什么,都不要更改循环迭代器的值(这里:i)。唯一应该改变值的地方是保持循环运行。否则改变它只是冒着一个例外的风险,在大多数情况下是不必要的。

检索/更新

检索数组的任意元素时,请始终根据数组的长度检查该元素是否为有效索引:

1
2
3
4
5
6
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到字符串数组长度的元素。name.length给出了字符串对象数组中字符串对象的数目,即3个,但最多只能访问索引2 name[2],因为数组可以从索引0访问到name.length - 1,在这里可以获得name.length个对象。

即使使用for循环,也应该从索引0开始,以name.length - 1结束。在数组a[n]中,您可以访问表单a[0]到[n-1]。

例如:

1
2
3
4
String[] a={"str1","str2","str3" ...,"strn"};

for(int i=0;i<a.length()i++)
    System.out.println(a[i]);

在您的情况下:

1
2
3
4
5
6
String[] name = {"tom","dick","harry"};

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'
'
);
}


对于给定的数组,数组的长度为3(即name.length=3)。但当它存储从索引0开始的元素时,它有最大索引2。

因此,您应该编写"i<**name.length"以避免出现"arrayindexoutofboundsException",而不是"i**<=name.length"。


由于i<=name.length部分的原因,您得到了ArrayIndexOutOfBoundsExceptionname.length返回字符串name的长度,即3。因此,当您试图访问name[3]时,这是非法的,并抛出了一个异常。

已解决代码:

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

它是在Java语言规范中定义的:

The public final field length, which contains the number of components
of the array. length may be positive or zero.


对于这个简单的问题,我只是想强调一下爪哇的一个新特性,它将避免数组中的所有混淆,即使对于初学者也是如此。Java-8已经为您抽象了迭代的任务。

1
2
3
4
5
6
7
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


Array index out of bounds exception

这就是在Eclipse中抛出此类异常时的外观。红色数字表示您试图访问的索引。所以代码应该是这样的:

1
myArray[5]

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

1
int[] intArray = new int[3];

那么唯一有效的索引是:

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

如果数组的长度为1,

1
int[] intArray = new int[1];

那么唯一有效的索引是:

1
intArray[0]

任何大于或等于数组长度的整数都超出界限。

小于0的任何整数:超出界限;

P.S.:如果你想更好地理解数组并做一些实际练习,这里有一个视频:Java中的数组教程


对于多维数组,确保访问正确维度的length属性可能比较困难。以下面的代码为例:

1
2
3
4
5
6
7
8
9
10
11
int [][][] a  = new int [2][3][4];

for(int i = 0; i < a.length; i++){
    for(int j = 0; j < a[i].length; j++){
        for(int k = 0; k < a[j].length; k++){
            System.out.print(a[i][j][k]);
        }
        System.out.println();
    }
    System.out.println();
}

每个维度都有不同的长度,因此细微的缺陷是中间和内部循环使用相同维度的length属性(因为a[i].lengtha[j].length相同)。

相反,为了简单起见,内部循环应该使用a[i][j].lengtha[0][0].length


arrayindexoutofboundsException每当出现此异常时,意味着您正在尝试使用超出其边界的数组索引,或者以非专业术语,您请求的索引超过了初始化的次数。

为了防止出现这种情况,请始终确保您没有请求数组中不存在的索引,即,如果数组长度为10,则索引的范围必须介于0到9之间。


对于看似神秘的arrayIndexOutofBoundsExceptions,我看到的最常见的情况是并发使用simpleDateFormat,这显然不是由您自己的数组处理代码引起的。特别是在servlet或控制器中:

1
2
3
4
5
6
7
public class MyController {
  SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");

  public void handleRequest(ServletRequest req, ServletResponse res) {
    Date date = dateFormat.parse(req.getParameter("date"));
  }
}

如果两个线程一起输入simplatedateformat.parse()方法,则可能会看到arrayIndexOutofBoundsException。注意类javadoc for simpledateformat的同步部分。

确保您的代码中没有位置可以像servlet或控制器那样以并发方式访问线程不安全类,如simpledateformat。检查您的servlet和控制器的所有实例变量是否存在可能的嫌疑。


arrayIndexOutofBounds意味着您正在尝试索引未分配的数组中的位置。

在这种情况下:

1
2
3
4
String[] name = {"tom","dick","harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length为3,因为数组已由3个字符串对象定义。
  • 访问数组内容时,位置从0开始。因为有3个项目,所以它的意思是name[0]="tom",name[1]="dick"和name[2]="harry
  • 当您循环时,因为我可以小于或等于name.length,所以您试图访问不可用的名称[3]。

为了避开这个…

  • 在for循环中,可以执行i

    for(int i = 0; i

  • 对每个循环使用

    江户十一〔一〕号

  • 使用list.foreach(消费者操作)(需要java8)

    埃多克斯1〔2〕

  • 将数组转换为流-如果您想对数组执行额外的"操作",例如筛选、转换文本、转换为映射等,这是一个很好的选择(需要java8)

    埃多克斯1〔3〕


ArrayIndexOutOfBoundsException表示您试图访问不存在或超出此数组边界的数组索引。数组索引从0开始,以长度-1结束。

在你的情况下

1
2
3
4
for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'
'
); // i goes from 0 to length, Not correct
}

当您试图访问时发生ArrayIndexOutOfBoundsException。不存在的name.length索引元素(数组索引以长度-1结尾)。只需将<=替换为<,就能解决这个问题。

1
2
3
4
for(int i = 0; i < name.length; i++) {
    System.out.print(name[i] +'
'
);  // i goes from 0 to length - 1, Correct
}

如果使用数组的长度来控制for循环的迭代,请始终记住数组中第一个项的索引为0。因此,数组中最后一个元素的索引小于数组的长度。


根据您的代码:

1
2
3
4
5
String[] name = {"tom","dick","harry"};
for(int i = 0; i<=name.length; i++) {
  System.out.print(name[i] +'
'
);
}

如果你查一下system.out.print(名称、长度);

你会得到3分;

也就是说你的名字长度是3

循环从0到3应该运行"0到2"或"1到3"

回答

1
2
3
4
5
String[] name = {"tom","dick","harry"};
for(int i = 0; i<name.length; i++) {
  System.out.print(name[i] +'
'
);
}


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

如果程序试图访问具有大于n-1的数组索引的任何元素(或内存),则Java将抛出

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

  • 维护计数:

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

    或者其他循环语句

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

  • 一个更好的方法是使用for-each循环,在这个方法中,程序员不需要为数组中的元素数量而烦恼。

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

  • 数组中的每个项称为元素,每个元素都通过其数字索引进行访问。如上图所示,编号以0开头。例如,第9个元素将在索引8中被访问。

    引发indexoutofboundsException以指示某种类型的索引(如数组、字符串或向量)超出范围。

    任何数组x,都可以从[0到(x.length-1)]


    我看到这里的所有答案,解释了如何使用数组以及如何避免索引越界异常。我个人不惜一切代价避免使用阵列。我使用Collections类,这样可以避免完全处理数组索引的愚蠢。循环构造与支持更容易编写、理解和维护的代码的集合完美结合。


    ArrayIndexOutOfBoundsException名称本身解释了,如果您试图访问超出数组大小范围的索引处的值,则会发生此类异常。

    在您的情况下,您可以从for循环中删除等号。

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

    更好的选择是迭代数组:

    1
    2
    for(String i : name )
          System.out.println(i);


    此错误发生在运行循环的过限时。让我们考虑这样的简单示例,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class demo{
      public static void main(String a[]){

        int[] numberArray={4,8,2,3,89,5};

        int i;

        for(i=0;i<numberArray.length;i++){
            System.out.print(numberArray[i+1]+" ");
        }
    }

    首先,我将数组初始化为"numberArray"。然后,使用for循环打印一些数组元素。当循环运行"i"时间时,打印(numberArray[i+1]元素..(当i值为1时,打印numberArray[i+1]元素。)…假设,当i=(numberArray.length-2)时,打印数组的最后一个元素..当"i"值转到(numberArray.length-1)时,不打印任何值..在该点上,发生"arrayindexoutofboundsException"。我希望您能有个主意。谢谢!


    不能重复或存储超过数组长度的数据。在这种情况下,您可以这样做:

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

    或者这个:

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