是什么导致java.lang.ArrayIndexOutOfBoundsException,如何防止它发生?


298

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

这是触发异常的代码示例:

String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
    System.out.println(names[i]);
}

1
关于最后一个问题,代码会有所帮助。您是在访问具有已知索引的数组,还是必须开始调试以找出发生错误时如何计算索引?
justkt 2011年

43
替换i <= name.lengthi < name.length-或更好,编写一个增强的for循环。(for (String aName : name) { ... }
Jean Hominal 2011年

1
这意味着,您要获取不存在的数组元素,'i <= name.length'意味着您要获取元素length + 1-该元素不存在。
gbk


Answers:


296

您的第一个停靠港应该是能够对其进行合理清晰解释的文档

抛出该错误指示数组已使用非法索引访问。索引为负或大于或等于数组的大小。

因此,例如:

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时引发异常。此处的有效索引为0-4(含0和4)。正确的惯用语for是:

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

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


1
我要补充一点,对于Java中可能具有任意形状的多维数组,嵌套循环应检查相关子数组的长度:for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }
Andrey

52
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];
}

也可以看看:


更新:根据您的代码段,

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

索引包括数组的长度。这是超出范围的。您需要替换<=<

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

22

摘自这篇出色的文章:for循环中的ArrayIndexOutOfBoundsException

简而言之:

在的最后一次迭代中

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

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

您的代码应阅读

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

17

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

例如,这将使用上限4初始化原始整数数组。

int intArray[] = new int[5];

程序员从零开始计数。因此,例如ArrayIndexOutOfBoundsException,当上限为4而不是5时,将抛出an 。

intArray[5];

4
界限是范围内的极限。即 0-5
John Giotta

11

为避免数组索引越界异常,应在可能的地方和时间使用增强的for语句。

主要动机(和用例)是当您进行迭代且不需要任何复杂的迭代步骤时。您将无法使用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");
}

11

是什么原因造成的ArrayIndexOutOfBoundsException

如果您将变量视为可以放置值的“盒子”,则数组是一系列彼此相邻放置的盒子,其中盒子的数量是有限且显式的整数。

创建一个像这样的数组:

final int[] myArray = new int[5]

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

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

myArray[3]

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

一个ArrayIndexOutOfBoundsException是由试图以检索一个“盒子”不存在,通过使指数比去年的“盒子”,或负的指数走高而引起的。

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

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++) {

请注意<,请勿=在其中混用。

您可能想尝试执行以下操作:

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

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

尽可能使用foreach:

for (int value : myArray) {

这样,您完全不必考虑索引。

循环时,无论您做什么,都不要更改循环迭代器的值(此处为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];
}

6

在您的代码中,您已经访问了从索引0到字符串数组长度的元素。name.length给出字符串对象数组中字符串对象的数量,即3,但是您最多只能访问索引2 name[2],因为可以从索引0到name.length - 1获取name.length对象数量的位置访问数组。

即使在使用for循环时,您也从索引0开始,应该以结束name.length - 1。在数组a [n]中,您可以访问形式a [0]到a [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');
}

5

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

因此,应该写'i <** name.length' 而不是'i ** <= name.length',以避免'ArrayIndexOutOfBoundsException'。


3

这个简单的问题就这么多了,但是我只是想重点介绍Java中的一项新功能,该功能可以避免即使对于初学者也能避免围绕数组索引的所有困惑。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


3

你正要ArrayIndexOutOfBoundsException分开i<=name.lengthname.length返回字符串的长度name,即3。因此,当您尝试访问时name[3],它是非法的并引发异常。

解决的代码:

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可以是正数或零。


3

数组索引超出范围异常

这就是在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:如果您希望对数组有更好的了解并进行一些实际练习,请在此处观看视频:Java数组教程


3

对于多维数组,确保访问length正确维的属性可能很棘手。以以下代码为例:

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].length与相同a[j].length)。

相反,内部循环应使用a[i][j].length(或a[0][0].length为简单起见,)。


为什么更改条件(多维数组)时为什么for循环不起作用添加了代码示例因为此问题被用作处理ArrayIndexOutOfBoundsException的任何问题的重复对象。
比尔蜥蜴

2

对于看似神秘的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"));
  }
}

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

确保您的代码中没有任何地方可以以并发方式(例如在servlet或控制器中)访问线程不安全类(例如SimpleDateFormat)。检查servlet和控制器的所有实例变量,以查找可能的可疑对象。


2

ArrayIndexOutOfBoundsException每当此异常即将到来时,就意味着您试图使用超出其范围的数组索引,或者以非专业人员的方式使用的数组所要求的数量比初始化的要多。

为避免这种情况,请始终确保您不请求数组中不存在的索引,即如果数组长度为10,则索引范围必须在0到9之间


2

ArrayIndexOutOfBounds表示您正在尝试索引未分配的数组中的位置。

在这种情况下:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length为3,因为已使用3个String对象定义了数组。
  • 当访问数组的内容时,位置从0开始。由于有3个项目,因此意味着name [0] =“ tom”,name [1] =“ dick”和name [2] =“ harry
  • 循环时,由于可以小于或等于name.length,因此您正在尝试访问不可用的name [3]。

为了解决这个问题...

  • 在您的for循环中,您可以执行<名称长度。这将防止循环到名称[3],而是停在名称[2]

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

  • 为每个循环使用

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

  • 使用list.forEach(Consumer action)(需要Java8)

    String[] name = { "tom", "dick", "harry" }; Arrays.asList(name).forEach(System.out::println);

  • 将数组转换为流-如果要对数组执行其他“操作”,例如过滤,转换文本,转换为地图等(需要Java8),这是一个不错的选择

    String[] name = { "tom", "dick", "harry" }; --- Arrays.asList(name).stream().forEach(System.out::println); --- Stream.of(name).forEach(System.out::println);


1

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

就你而言

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

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

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

1

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

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

所以这是我们可以在程序中使用的两个解决方案

  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(String str : array) {
        System.out.println(str);
    }

1

根据您的代码:

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

如果您检查System.out.print(name.length);

你会得到3;

那意味着你的名字长度是3

您的循环从0到3运行,应该运行“ 0到2”或“ 1到3”

回答

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

1

数组中的每个项目都称为一个元素,每个元素都可以通过其数字索引进行访问。如上图所示,编号从0开始。例如,第9个元素因此将在索引8处访问。

抛出IndexOutOfBoundsException以指示某种索引(例如,数组,字符串或向量)超出范围。

可以从[0到(X.length-1)]访问任何数组X


1

我在这里看到所有答案,解释了如何使用数组以及如何避免索引超出范围异常。我个人不惜一切代价避免使用数组。我使用Collections类,这避免了必须完全处理数组索引的所有愚蠢行为。循环结构与支持代码的集合完美配合,使代码更易于编写,理解和维护。


1

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


0

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

就您而言,您只需从for循环中删除等号。

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

更好的选择是迭代数组:

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

0

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

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'。希望idea。谢谢!


0

您可以在函数样式中使用Optional来避免NullPointerExceptionArrayIndexOutOfBoundsException

String[] array = new String[]{"aaa", null, "ccc"};
for (int i = 0; i < 4; i++) {
    String result = Optional.ofNullable(array.length > i ? array[i] : null)
            .map(x -> x.toUpperCase()) //some operation here
            .orElse("NO_DATA");
    System.out.println(result);
}

输出:

AAA
NO_DATA
CCC
NO_DATA

-4

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

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

或这个:

for (int i = 0; i < name.length; i++) {
    // ...
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.