341

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

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

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

26 回答 26

324

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

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

例如:

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 (含)。这里正确的惯用for语句是:

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

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

于 2011-04-05T15:57:47.950 回答
57
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++) {
于 2011-04-05T15:59:48.807 回答
24

来自这篇优秀的文章:ArrayIndexOutOfBoundsException in for loop

简单地说:

在最后一次迭代中

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

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

您的代码应阅读

for (int i = 0; i < name.length; i++) 
                  ^
于 2011-04-05T16:15:09.657 回答
18

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

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

int intArray[] = new int[5];

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

intArray[5];
于 2011-04-05T15:55:57.303 回答
14

什么原因ArrayIndexOutOfBoundsException

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

像这样创建一个数组:

final int[] myArray = new int[5]

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

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

myArray[3]

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

AnArrayIndexOutOfBoundsException是由于试图检索一个不存在的“盒子”,通过传递一个高于最后一个“盒子”的索引或负数的索引而引起的。

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

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

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

循环时,无论您做什么,都不要更改循环迭代器的值(此处: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];
}
于 2016-01-19T16:55:56.130 回答
12

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

主要动机(和用例)是当您进行迭代并且不需要任何复杂的迭代步骤时。您将无法使用增强型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");
}
于 2015-10-16T21:45:56.977 回答
8

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

即使在使用for循环时,您也从索引零开始,您应该以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');
}
于 2017-06-21T04:57:45.950 回答
6

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

所以,你应该写 'i <**name.length'而不是 'i**<= name.length ' 以避免出现 'ArrayIndexOutOfBoundsException'。

于 2018-01-16T12:13:33.670 回答
4

这个简单的问题就这么多,但我只想强调 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

于 2017-10-25T07:38:27.887 回答
3

你得到ArrayIndexOutOfBoundsExceptioni<=name.length部分。name.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可能是正数或零。

于 2017-03-06T09:00:11.350 回答
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 数组教程

于 2017-03-08T12:56:12.577 回答
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,为简单起见)。

于 2018-06-12T19:41:38.850 回答
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 和控制器的所有实例变量以查找可能的嫌疑人。

于 2011-04-05T16:06:37.413 回答
2

对于任何长度为 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 each 循环,在这种方法中,程序员无需担心数组中元素的数量。

    for(String str : array) {
        System.out.println(str);
    }
    
于 2016-11-11T08:21:57.430 回答
2

ArrayIndexOutOfBoundsException 每当出现此异常时,这意味着您正在尝试使用超出其范围的数组索引,或者用外行术语来说,您请求的数量超过了您的初始化。

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

于 2018-09-15T10:29:18.843 回答
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
  • 当您循环时,由于i可以小于或等于 name.length,因此您正在尝试访问不可用的 name[3]。

为了解决这个...

  • 在您的 for 循环中,您可以执行 i < name.length。这将防止循环到 name[3],而是在 name[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);

于 2018-12-14T00:08:46.087 回答
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
}
于 2017-11-30T16:41:17.060 回答
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');
}
于 2018-03-26T08:08:39.740 回答
1

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

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

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

于 2018-10-18T09:24:27.117 回答
1

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

于 2018-11-13T18:08:23.130 回答
1

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

于 2019-04-12T02:43:06.933 回答
0

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

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

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

更好的选择是迭代一个数组:

for(String i : name )
      System.out.println(i);
于 2018-05-17T03:27:58.323 回答
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.长度-2),数组的最后一个元素被打印。当'i'值变为(numberArray.length-1)时,没有打印值..在那一点,'ArrayIndexOutOfBoundsException'发生。我希望你能得到想法。谢谢!

于 2018-07-17T03:03:45.547 回答
0

您可以在功能样式中使用 Optional 来避免NullPointerExceptionand ArrayIndexOutOfBoundsException

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
于 2019-09-17T12:16:03.997 回答
-1

在大多数编程语言中,索引都是从 0 开始的。所以你必须写i<names.lengthi<=names.length-1而不是i<=names.length

于 2021-02-16T08:04:28.433 回答
-4

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

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

或这个:

for (int i = 0; i < name.length; i++) {
    // ...
}
于 2016-01-19T16:26:00.243 回答