What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
下面是触发异常的代码示例:
1 2 3 4 |
您的第一个停靠港应该是能够合理清晰地解释这一点的文档:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
号
例如:
1 2 | int[] array = new int[5]; int boom = array[10]; // Throws the exception |
至于如何避免它…嗯,别这样。小心数组索引。
人们有时会遇到的一个问题是认为数组是单索引的,例如
1 2 3 4 5 6 | 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。这里的正确、惯用的
1 | for (int index = 0; index < array.length; index++) |
(当然,这是假设你需要索引。如果您可以使用增强的for循环,请执行此操作。)
1 2 3 4 5 6 | 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]; } |
。另请参见:
- Java教程-语言基础-数组
更新:根据代码片段,
1 | for (int i = 0; i<=name.length; i++) { |
。
索引包含数组的长度。这是越界的。你需要用
1 | for (int i = 0; i < name.length; i++) { |
简而言之:
在的最后一个迭代中
1 | for (int i = 0; i <= name.length; i++) { |
你的代码应该是
1 2 | for (int i = 0; i < name.length; i++) ^ |
。
这意味着您正试图访问数组的索引,该索引无效,因为它不在边界之间。
例如,这将初始化一个上界为4的基元整数数组。
1 | int intArray[] = new int[5]; |
程序员从零开始计数。所以这个例子会抛出一个
1 | intArray[5]; |
号
为了避免数组索引越界异常,应该在可能的位置和时间使用增强型-
主要的动机(和用例)是当您在迭代时,您不需要任何复杂的迭代步骤。您将无法使用增强的-
在执行此操作时,保证不会耗尽要迭代的元素,并且您的[corrected]示例很容易转换。
代码如下:
1 2 3 4 5 |
号
…相当于:
1 2 3 4 5 |
号
是什么导致了
如果你把一个变量看作是一个"框",你可以在其中放置一个值,那么数组就是一系列放置在每个框旁边的框,框的数量是一个有限的显式整数。
创建这样的数组:
1 | final int[] myArray = new int[5] |
创建一行5个框,每个框包含一个
要从这一系列框中检索其中一个值,可以通过其索引引用它,如下所示:
1 | myArray[3] |
号
它将为您提供系列中第4个框的值(因为第一个框的索引为0)。
在我的运行示例中,这些代码片段将产生这样一个异常:
1 2 3 | myArray[5] //tries to retrieve the 6th"box" when there is only 5 myArray[-1] //just makes no sense myArray[1337] //waay to high |
如何避免
为了防止
循环
循环遍历数组时,始终确保要检索的索引严格小于数组的长度(框数)。例如:
1 | for (int i = 0; i < myArray.length; i++) { |
。
注意
你可能想做这样的事情:
1 2 | for (int i = 1; i <= myArray.length; i++) { final int someint = myArray[i - 1] |
不要这样做。坚持上面的那个(如果你需要使用索引的话),它会让你省去很多痛苦。
如有可能,使用foreach:
1 | for (int value : myArray) { |
。
这样就不必考虑索引了。
循环时,无论您做什么,都不要更改循环迭代器的值(这里:
检索/更新
检索数组的任意元素时,请始终根据数组的长度检查该元素是否为有效索引:
1 2 3 4 5 6 | 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]; } |
。
在代码中,您已经访问了从索引0到字符串数组长度的元素。
即使使用
例如:
1 2 3 4 |
在您的情况下:
1 2 3 4 5 6 |
号
对于给定的数组,数组的长度为3(即name.length=3)。但当它存储从索引0开始的元素时,它有最大索引2。
因此,您应该编写"i<**name.length"以避免出现"arrayindexoutofboundsException",而不是"i**<=name.length"。
由于
已解决代码:
1 2 3 4 5 |
。
它是在Java语言规范中定义的:
The
public final fieldlength , which contains the number of components
of the array.length may be positive or zero.
号
对于这个简单的问题,我只是想强调一下爪哇的一个新特性,它将避免数组中的所有混淆,即使对于初学者也是如此。Java-8已经为您抽象了迭代的任务。
1 2 3 4 5 6 7 | 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]); }) |
有什么好处?嗯,有一点是可读性,比如英语。第二,你不必担心
。
这就是在Eclipse中抛出此类异常时的外观。红色数字表示您试图访问的索引。所以代码应该是这样的:
1 | myArray[5] |
号
尝试访问该数组中不存在的索引时引发错误。如果一个数组的长度为3,
1 | int[] intArray = new int[3]; |
号
那么唯一有效的索引是:
1 2 3 | intArray[0] intArray[1] intArray[2] |
号
如果数组的长度为1,
1 | int[] intArray = new int[1]; |
号
那么唯一有效的索引是:
1 | intArray[0] |
号
任何大于或等于数组长度的整数都超出界限。
小于0的任何整数:超出界限;
P.S.:如果你想更好地理解数组并做一些实际练习,这里有一个视频:Java中的数组教程
对于多维数组,确保访问正确维度的
1 2 3 4 5 6 7 8 9 10 11 |
每个维度都有不同的长度,因此细微的缺陷是中间和内部循环使用相同维度的
相反,为了简单起见,内部循环应该使用
arrayindexoutofboundsException每当出现此异常时,意味着您正在尝试使用超出其边界的数组索引,或者以非专业术语,您请求的索引超过了初始化的次数。
为了防止出现这种情况,请始终确保您没有请求数组中不存在的索引,即,如果数组长度为10,则索引的范围必须介于0到9之间。
对于看似神秘的arrayIndexOutofBoundsExceptions,我看到的最常见的情况是并发使用simpleDateFormat,这显然不是由您自己的数组处理代码引起的。特别是在servlet或控制器中:
1 2 3 4 5 6 7 | 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。注意类javadoc for simpledateformat的同步部分。
确保您的代码中没有位置可以像servlet或控制器那样以并发方式访问线程不安全类,如simpledateformat。检查您的servlet和控制器的所有实例变量是否存在可能的嫌疑。
arrayIndexOutofBounds意味着您正在尝试索引未分配的数组中的位置。
在这种情况下:
1 2 3 4 |
- name.length为3,因为数组已由3个字符串对象定义。
- 访问数组内容时,位置从0开始。因为有3个项目,所以它的意思是name[0]="tom",name[1]="dick"和name[2]="harry
- 当您循环时,因为我可以小于或等于name.length,所以您试图访问不可用的名称[3]。
为了避开这个…
在for循环中,可以执行i
for(int i = 0; i 。 对每个循环使用
江户十一〔一〕号
使用list.foreach(消费者操作)(需要java8)
埃多克斯1〔2〕
将数组转换为流-如果您想对数组执行额外的"操作",例如筛选、转换文本、转换为映射等,这是一个很好的选择(需要java8)
埃多克斯1〔3〕
在你的情况下
1 2 3 4 | for(int i = 0; i<=name.length; i++) { System.out.print(name[i] +' '); // i goes from 0 to length, Not correct } |
。
当您试图访问时发生
1 2 3 4 | for(int i = 0; i < name.length; i++) { System.out.print(name[i] +' '); // i goes from 0 to length - 1, Correct } |
如果使用数组的长度来控制for循环的迭代,请始终记住数组中第一个项的索引为0。因此,数组中最后一个元素的索引小于数组的长度。
根据您的代码:
1 2 3 4 5 |
。
如果你查一下system.out.print(名称、长度);
你会得到3分;
也就是说你的名字长度是3
循环从0到3应该运行"0到2"或"1到3"
回答
1 2 3 4 5 |
。
对于长度为n的任何数组,数组的元素将具有从0到n-1的索引。
如果程序试图访问具有大于n-1的数组索引的任何元素(或内存),则Java将抛出
所以这里有两个解决方案,我们可以在程序中使用
维护计数:
1 2 3 |
或者其他循环语句
1 2 3 4 5 |
。
一个更好的方法是使用for-each循环,在这个方法中,程序员不需要为数组中的元素数量而烦恼。
数组中的每个项称为元素,每个元素都通过其数字索引进行访问。如上图所示,编号以0开头。例如,第9个元素将在索引8中被访问。
引发indexoutofboundsException以指示某种类型的索引(如数组、字符串或向量)超出范围。
任何数组x,都可以从[0到(x.length-1)]
我看到这里的所有答案,解释了如何使用数组以及如何避免索引越界异常。我个人不惜一切代价避免使用阵列。我使用Collections类,这样可以避免完全处理数组索引的愚蠢。循环构造与支持更容易编写、理解和维护的代码的集合完美结合。
在您的情况下,您可以从for循环中删除等号。
1 | for(int i = 0; i<name.length; i++) |
更好的选择是迭代数组:
。
此错误发生在运行循环的过限时。让我们考虑这样的简单示例,
1 2 3 4 5 6 7 8 9 10 11 |
。
首先,我将数组初始化为"numberArray"。然后,使用for循环打印一些数组元素。当循环运行"i"时间时,打印(numberArray[i+1]元素..(当i值为1时,打印numberArray[i+1]元素。)…假设,当i=(numberArray.length-2)时,打印数组的最后一个元素..当"i"值转到(numberArray.length-1)时,不打印任何值..在该点上,发生"arrayindexoutofboundsException"。我希望您能有个主意。谢谢!
不能重复或存储超过数组长度的数据。在这种情况下,您可以这样做:
1 2 3 | for (int i = 0; i <= name.length - 1; i++) { // .... } |
号
或者这个:
1 2 3 | for (int i = 0; i < name.length; i++) { // ... } |
号