什么导致java.lang.ArrayIndexOutOfBoundsException,我该如何防止它?
ArrayIndexOutOfBoundsException
是什么意思,我该如何摆脱它?
以下是触发exception的代码示例:
String[] name = {"tom", "dick", "harry"}; for(int i = 0; i<=name.length; i++) { System.out.print(name[i] +'\n'); }
你的第一个停靠港应该是合理清楚地解释它的文件 :
抛出以指示已经使用非法索引访问数组。 该索引是否定的或者大于或等于数组的大小。
举个例子:
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时抛出一个exception。这里的有效索引是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]; }
也可以看看:
- Java教程 – 语言基础 – 数组
更新 :根据你的代码片段,
for(int i = 0; i<=name.length; i++) {
索引包含数组的长度。 这是超出界限的。 你需要用<=
replace<=
。
for(int i = 0; i < name.length; i++) {
简要说一下:
在最后一次迭代中
for(int i = 0; i<=name.length; i++) {
i
将等于name.length
这是一个非法的指数,因为数组索引是从零开始的。
你的代码应该阅读
for(int i = 0; i < name.length; i++) ^
这意味着你正试图访问一个数组的索引,因为它不在边界之间。
例如,这将初始化一个上限为4的原始整型数组。
int intArray[] = new int[5];
程序员从零开始计数。 所以这个例子会抛出一个ArrayIndexOutOfBoundsException
因为上限是4而不是5。
intArray[5];
为了避免数组索引超出范围的exception,应该在何时何地可以使用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"); }
什么导致ArrayIndexOutOfBoundsException
?
如果你把一个variables想象成一个可以放置一个值的“盒子”,那么一个数组就是一系列放在彼此旁边的盒子,盒子的数量是一个有限的显式整数。
像这样创build一个数组:
final int[] myArray = new int[5]
创build一行5个框,每个框持有一个int
。 每个方框都有一个索引,一系列方框中的一个位置。 该索引从0开始,并在N-1结束,其中N是数组的大小(框的数量)。
要从这一系列框中检索其中一个值,可以通过索引来引用它,如下所示:
myArray[3]
这将给你的系列中的第四个框的值(因为第一个框的索引为0)。
ArrayIndexOutOfBoundsException
是由于尝试通过传递比最后一个“box”的索引更高的索引或负数来检索不存在的“框”而引起的。
以我的运行示例,这些代码片段会产生这样一个例外:
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) {
这样你就不必考虑索引了。
循环时,不pipe你做什么,都不要改变循环迭代器的值(这里是: 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]; }
在你的代码中,你已经访问了从索引0到string数组长度的元素。 name.length
给出了string对象数组中的string对象的数量,即3,但是只能访问到索引2的name[2]
,因为数组可以从索引0访问到name.length - 1
, name.length
对象的数量。
即使在使用for循环的时候,你已经开始使用索引零,你应该以name.length - 1
结束。 在数组a [n]中,您可以访问从[0]到[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中的新function,这将避免所有在数组中的索引混淆,即使是初学者。 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
我所见过的看起来很神秘的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")); } }
如果两个线程一起inputSimplateDateFormat.parse()方法,您可能会看到ArrayIndexOutOfBoundsException。 请注意SimpleDateFormat的类javadoc的同步部分。
确保在你的代码中没有任何地方是像servlet或控制器那样以并发的方式访问像SimpleDateFormat这样的线程不安全的类。 检查您的servlets程序和控制器的所有实例variables可能的嫌疑人。
对于任何长度为n的数组,数组的元素将具有从0到n-1的索引。
如果你的程序试图访问数组索引大于n-1的任何元素(或内存),那么java将抛出ArrayIndexOutOfBoundsException
所以这里有两个解决scheme,我们可以在程序中使用
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); }
由于i<=name.length
部分,您将获得ArrayIndexOutOfBoundsException
。 name.length
返回stringname
的长度,即3。因此当你试图访问name[3]
,它的非法并抛出exception。
解决的代码:
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
可能是正数或零。
这就是这种types的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的整数都是越界的;
PS如果你对数组有更好的理解并做一些实际的练习,这里有一个video: 关于java中数组的教程
您不能迭代或存储比数组长度更多的数据。 在这种情况下,你可以这样做:
for (int i = 0; i <= name.length - 1; i++) { // .... }
或这个:
for (int i = 0; i < name.length; i++) { // ... }