什么原因导致 java.lang.ArrayIndexOutOfBoundsException,如何防止它?

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

提问人:Aaron 提问时间:4/5/2011 最后编辑:Alexander IvanchenkoAaron 更新时间:7/23/2023 访问量:988114

问:

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

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

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

评论

1赞 justkt 4/5/2011
关于最后一个问题,代码会有所帮助。您是使用已知索引访问数组,还是必须开始调试以弄清楚发生错误时索引的计算方式?
51赞 Jean Hominal 4/6/2011
替换为 - 或更好的是,编写一个增强的 for 循环。(i <= name.lengthi < name.lengthfor (String aName : name) { ... })
2赞 hbk 2/23/2013
这意味着,你想获取不存在的数组元素,“i<=name.length”意味着你想获取元素长度+1 - 它不存在。
1赞 sakhunzai 4/18/2017
en.wikipedia.org/wiki/Off-by-one_error
0赞 Jyotirmay 3/26/2020
当您尝试操作的索引大于数组的长度时,数组将越界。为了正确起见,您的索引应始终比总数少 1。数组元素,因为数组索引从 0 而不是 1 开始。

答:

19赞 Octavian Helm 4/5/2011 #1

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

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

int intArray[] = new int[5];

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

intArray[5];

评论

5赞 John Giotta 4/5/2011
边界是范围内的限制。即;0-5
345赞 Jon Skeet 4/5/2011 #2

你的第一站应该是合理清楚地解释它的文档

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

例如:

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 循环,请这样做。

评论

4赞 Andrey 3/3/2017
我要补充一点,对于在 Java 中可能具有任意形状的多维数组,嵌套循环应该检查相关的子数组长度:.for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }
0赞 rghome 12/8/2021
可以在答案中提到,应查阅堆栈跟踪以查找发生错误的确切行。IMO,这是第一个停靠港。
0赞 Jon Skeet 12/8/2021
@rghome:不过,这并不是对“ArrayIndexOutOfBoundsException 是什么意思”的回答。我认为在尝试理解代码中的原因之前,您需要了解它的含义。如果我告诉你,在给定的代码行中有一个 GrobulatorError,如果你不知道 GrobulatorError 是什么,你将如何确定导致它的原因?
0赞 rghome 12/8/2021
是的 - 但是。我们得到很多这样的链接,需要找到一个链接来接近重复。通常,OP 甚至没有确定它发生在哪一行代码上。关于如何分析堆栈跟踪还有另一个问题,但我认为最好有一个单一的过程来查找 IOOB,这样有人就可以确信 OP 可以通过链接自行解决它。
0赞 Jon Skeet 12/8/2021
@rghome:一个规范的问答听起来不错,但我认为这不一定是正确的。或者,即使它是正确的,我仍然会说,首先要做的是了解错误的含义,然后再查看您的代码以了解它发生的原因。
61赞 BalusC 4/5/2011 #3

基本上:

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

另请参阅:

3赞 Kyri Sarantakos 4/6/2011 #4

对于看似神秘的 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 和控制器的所有实例变量,以查找可能的可疑对象。

29赞 aioobe 4/6/2011 #5

来自这篇优秀的文章:for 循环中的 ArrayIndexOutOfBoundsException

简而言之:

在上一次迭代中

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

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

您的代码应为

for (int i = 0; i < name.length; i++) 
                  ^
13赞 Makoto 10/17/2015 #6

为了避免数组索引越界异常,应该在可能的情况下使用 enhanced-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");
}
15赞 Tobb 1/20/2016 #7

什么原因导致 ArrayIndexOutOfBoundsException

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

创建一个像这样数组:

final int[] myArray = new int[5]

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

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

myArray[3]

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

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

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

myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //way 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];
}
2赞 Mohit 11/11/2016 #8

对于任何长度为 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);
    }
    
3赞 roottraveller 3/6/2017 #9

你正在得到部分。 返回字符串的长度,即 3。因此,当您尝试访问 时,这是非法的,并引发异常。ArrayIndexOutOfBoundsExceptioni<=name.lengthname.lengthnamename[3]

已解决的代码:

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

它在 Java 语言规范中定义:

字段 ,其中包含组件数 的数组。 可能为正数或零。public finallengthlength

3赞 Johny 3/8/2017 #10

Array index out of bounds 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 的整数:越界;

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

9赞 Madhusudan chowdary 6/21/2017 #11

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

即使在使用循环时,您也以索引 0 开头,并且应该以 .在数组 a[n] 中,您可以访问形式 a[0] 到 a[n-1]。forname.length - 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');
}
4赞 Satyendra Kumar 10/25/2017 #12

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

2赞 adn.911 12/1/2017 #13

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
}
7赞 nIKHIL 1/16/2018 #14

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

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

1赞 Abhishek Agarwal 3/26/2018 #15

根据您的代码:

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

如果您检查 System.out.print(名称长度);

你会得到 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');
}
0赞 Madhusudan Sharma 5/17/2018 #16

ArrayIndexOutOfBoundsExceptionname 本身解释说,如果您尝试访问超出 Array size 范围的索引处的值,则会发生此类异常。

在您的例子中,您可以从 for 循环中删除等号。

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

更好的选择是迭代数组:

for(String i : name )
      System.out.println(i);
3赞 Bill the Lizard 6/13/2018 #17

对于多维数组,确保访问正确维度的属性可能很棘手。以以下代码为例: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();
}

每个维度都有不同的长度,所以微妙的错误是中间和内部循环使用相同维度的属性(因为与 相同)。lengtha[i].lengtha[j].length

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

评论

0赞 Bill the Lizard 6/13/2018
添加了为什么我的 for 循环在更改条件(多维数组)时不起作用? 中的代码示例,因为此问题被用作处理 ArrayIndexOutOfBoundsException 的任何问题的重复目标。
-1赞 Gayan Sampath 7/17/2018 #18

此错误发生在运行循环超出限制时间时。让我们考虑一个简单的例子,

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'。我希望你能得到想法,谢谢!

2赞 sgrpwr 9/15/2018 #19

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

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

1赞 ZiadM 10/18/2018 #20

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

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

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

1赞 John Czukkermann 11/14/2018 #21

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

2赞 user10486861 12/14/2018 #22

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

在这种情况下:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length 为 3,因为数组已使用 3 个 String 对象定义。
  • 访问数组的内容时,position 从 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++)

  • 使用 for each 循环

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

0赞 Sachithra Dilshan 4/12/2019 #23

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

-1赞 Andrey Lavrukhin 9/17/2019 #24

您可以在函数样式中使用 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
-1赞 Dhanushka Sampath 7/23/2023 #25

当您尝试访问不存在的数组的索引时,会发生 ArrayIdexOutOfBoundException。在 i = 3 的场景中,您尝试检索 names 数组的第 3 个索引。但是 names 数组最多保存第二个索引的值。

由于数组的第 3 个索引处没有值,因此会引发此异常。