【问题标题】:What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?是什么导致了 java.lang.ArrayIndexOutOfBoundsException 异常?我该如何预防?
【发布时间】:2022-12-06 01:33:46
【问题描述】:

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

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

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

【问题讨论】:

  • 关于最后一个问题,代码会有所帮助。您是在访问具有已知索引的数组,还是必须开始调试以弄清楚发生错误时索引是如何计算的?
  • i &lt;= name.length 替换为 i &lt; name.length - 或者更好,编写一个增强的 for 循环。 (for (String aName : name) { ... })
  • 这意味着,您想要获取不存在的数组元素,'i<=name.length' 意味着您想要获取元素长度+1 - 它不存在。
  • 当您尝试操作的索引超过数组的长度时,数组就会越界。为了正确起见,您的索引应始终比总数少一个。数组元素,因为数组索引从 0 而不是 1 开始。

标签: java arrays exception arrayindexoutofboundsexception


【解决方案1】:

您的第一个停靠港应该是documentation,它解释得相当清楚:

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

例如:

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

【讨论】:

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

也可以看看:


更新: 根据您的代码 sn-p,

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

索引包括数组的长度。这是越界的。您需要将 &lt;= 替换为 &lt;

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

【讨论】:

    【解决方案3】:

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

    简而言之:

    在最后一次迭代中

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

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

    你的代码应该阅读

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

    【讨论】:

      【解决方案4】:

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

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

      int intArray[] = new int[5];
      

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

      intArray[5];
      

      【讨论】:

      • 边界是范围内的限制。 IE。; 0-5
      【解决方案5】:

      是什么导致ArrayIndexOutOfBoundsException

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

      像这样创建一个数组:

      final int[] myArray = new int[5]
      

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

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

      myArray[3]
      

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

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

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

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

      注意&lt;,永远不要在里面混用=..

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

      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】:

        为避免数组索引越界异常,应尽可能使用 enhanced-for 语句。

        主要动机(和用例)是在迭代时不需要任何复杂的迭代步骤。你会不是能够使用 enhanced-for 在数组中向后移动或仅迭代所有其他元素。

        执行此操作时,您保证不会用完要迭代的元素,并且您的 [更正] 示例很容易转换。

        下面的代码:

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

        ...等同于:

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

        【讨论】:

          【解决方案7】:

          在您的代码中,您访问了从索引 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] +'
          ');
          }
          

          【讨论】:

            【解决方案8】:

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

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

            【讨论】:

              【解决方案9】:

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

              【讨论】:

                【解决方案10】:

                我见过的看似神秘的 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。注意class javadoc for SimpleDateFormat 的同步部分。

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

                【讨论】:

                  【解决方案11】:

                  由于 i&lt;=name.length 部分,您将获得 ArrayIndexOutOfBoundsExceptionname.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] +'
                  ');
                  }
                  

                  它在Java language specification 中定义:

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

                  【讨论】:

                    【解决方案12】:

                    这就是在 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.:如果你想更好地理解数组并做一些实际练习,这里有一个视频:tutorial on arrays in Java

                    【讨论】:

                      【解决方案13】:

                      对于多维数组,确保访问正确维度的 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].lengtha[j].length相同)。

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

                      【讨论】:

                      【解决方案14】:

                      对于任何长度为 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);
                        }
                        

                      【讨论】:

                        【解决方案15】:

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

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

                        【讨论】:

                          【解决方案16】:

                          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" and name[2]="harry
                          • 当你循环时,因为一世可以小于或等于 name.length,您正在尝试访问不可用的 name[3]。

                          为了解决这个...

                          • 在你的 for 循环中,你可以做 i < name.length。这将防止循环到 name[3],而是在 name[2] 处停止

                            for(int i = 0; i&lt;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);

                          【讨论】:

                            【解决方案17】:

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

                            在你的情况下

                            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 结束)。只需将 <= 替换为 < 即可解决此问题。

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

                            【讨论】:

                              【解决方案18】:

                              根据您的代码:

                              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”

                              回答

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

                              【讨论】:

                                【解决方案19】:

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

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

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

                                【讨论】:

                                  【解决方案20】:

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

                                  【讨论】:

                                    【解决方案21】:

                                    如果您使用数组的长度来控制 a 的迭代为了循环,永远记住数组中第一项的索引是0.所以数组中最后一个元素的索引比数组的长度小一个。

                                    【讨论】:

                                      【解决方案22】:

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

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

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

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

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

                                      【讨论】:

                                        【解决方案23】:

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

                                        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] 元素。).. length-2),打印数组的最后一个元素。当'i'值变为(numberArray.length-1)时,没有打印值..在那个时候,发生'ArrayIndexOutOfBoundsException'。我希望你能得到想法。谢谢!

                                        【讨论】:

                                          【解决方案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
                                          

                                          【讨论】:

                                            【解决方案25】:

                                            在大多数编程语言中索引都是从 0 开始的。所以你必须要写我<名称.长度或者i<=names.length-1代替我<=名字.长度.

                                            【讨论】:

                                            • 这个问题与“大多数”编程语言无关。它是关于 Java 的。 (无论如何,10 年前投票最多/接受的答案就是这样说的。)
                                            【解决方案26】:

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

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

                                            或这个:

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

                                            【讨论】:

                                              猜你喜欢
                                              • 1970-01-01
                                              • 2021-03-07
                                              相关资源
                                              最近更新 更多