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

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

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

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

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

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

int intArray[] = new int[5];

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

intArray[5];

你的第一个调用端口应该是文档,它合理地解释了它:

抛出,表示使用非法索引访问了数组。索引值为负或大于或等于数组的大小。

例如:

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

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

我所见过的看似神秘的arrayindexoutofboundsexception最常见的情况,即显然不是由您自己的数组处理代码引起的,是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类. xml文件的同步部分。

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

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

简单来说:

在最后的迭代中

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

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

您的代码应该如下所示

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

为了避免数组下标越界异常,应该在可以使用的地方和时候使用增强-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");
}

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

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

或:

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

是什么导致了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];
}

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

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

这里有两种我们可以在程序中使用的解决方案

  1. < p >维护数:

    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. A better way go with a for each loop, in this method a programmer has no need to bother about the number of elements in the array.

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

由于i<=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] +'\n');
}

它在Java语言规范中定义:

public final字段length,包含组件的数量 数组的。length可以为正或零

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的整数:都是越界的;

附注:如果你希望更好地理解数组并做一些实际练习,这里有一个视频:Java数组教程

在你的代码中,你已经访问了从索引0到字符串数组长度的元素。name.length给出了字符串对象数组中字符串对象的数量,即3,但你只能访问到索引2 name[2], 因为数组可以从索引0到name.length - 1访问,在这里你可以得到name.length个对象的数量

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

这个简单的问题就讲到这里,我只想强调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

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当你试图访问时发生 这个名字。长度索引的元素不存在(数组索引以长度-1结束)。只是用<就能解决这个问题。< / p >

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

对于给定的数组,数组的长度是3。的名字。但是因为它存储的是从索引0开始的元素,所以它的最大索引是2。

所以,不是'i**<=的名字。长度'你应该写成'i<**name。长度',以避免'ArrayIndexOutOfBoundsException'。

根据贵公司守则:

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

如果你检查 System.out.print (name.length); < / p >

你会得到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');
}

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

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

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

更好的选择是迭代数组:

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

对于多维数组,要确保访问正确维度的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,为简单起见)。

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

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。我希望你能明白。谢谢你!

每当这个异常出现时,它意味着你正在尝试使用一个超出界限的数组索引,或者在外行术语中,你正在请求比你初始化的更多。

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

数组中的每一项都称为一个元素,每个元素都通过它的数值索引来访问。如前面的插图所示,编号从0开始.;例如,第9个元素将因此在索引8处被访问。

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

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

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

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

在这种情况下:

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

为了解决这个问题…

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

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

  • 每个循环使用a

    < p > <代码> String [] name ={“汤姆”、“迪克”、“哈利”}; for(字符串n: name) { System.out.println (n); 代码}< / > < / p > < /李>
  • < p >使用列表。forEach(消费者操作)(需要Java8)

    < p > <代码> String [] name ={“汤姆”、“迪克”、“哈利”}; arrays . aslist(名字).forEach (system . out:: println); < /代码> < / p > < /李>
  • 转换数组到流-这是一个很好的选择,如果你想执行额外的“操作”到你的数组,例如过滤器,转换文本,转换为一个地图等(需要Java8)

    < p > <代码> String [] name ={“汤姆”、“迪克”、“哈利”}; ——arrays . aslist(名字).stream () .forEach (system . out:: println); ——Stream.of(名字).forEach (system . out:: println); < /代码> < / p > < /李>

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

你可以在函数式中使用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

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