提问人:Aaron 提问时间:4/5/2011 最后编辑:Alexander IvanchenkoAaron 更新时间:7/23/2023 访问量:987015
是什么导致了java.lang.ArrayIndexOutOfBoundsException,我该如何防止它?
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
问:
这是什么意思,我该如何摆脱它?ArrayIndexOutOfBoundsException
下面是触发异常的代码示例:
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
System.out.println(names[i]);
}
答:
这意味着您正在尝试访问数组的索引,该索引无效,因为它不在边界之间。
例如,这将初始化一个上限为 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(含 0-4)。这里正确的惯用语是:for
for (int index = 0; index < array.length; index++)
(当然,这是假设你需要索引。如果可以改用增强的 for 循环,请这样做。
评论
for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }
基本上:
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++)
另请参阅:
对于看似神秘的 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 和控制器的所有实例变量,以查找可能的可疑对象。
来自这篇优秀的文章:for 循环中的 ArrayIndexOutOfBoundsException
简而言之:
在上一次迭代中
for (int i = 0; i <= name.length; i++) {
i
将等于非法索引,因为数组索引是从零开始的。name.length
您的代码应为
for (int i = 0; i < name.length; i++)
^
为了避免数组索引越界异常,应该在可能的情况下使用 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");
}
什么原因导致 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];
}
对于任何长度为 n 的数组,数组元素的索引将从 0 到 n-1。
如果您的程序尝试访问数组索引大于 n-1 的任何元素(或内存),那么 Java 将抛出 ArrayIndexOutOfBoundsException
因此,我们可以在程序中使用两种解决方案
保持计数:
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++; }
更好的方法是使用每个循环,在这种方法中,程序员无需为数组中的元素数量而烦恼。
for(String str : array) { System.out.println(str); }
你正在得到部分。 返回字符串的长度,即 3。因此,当您尝试访问 时,这是非法的,并引发异常。ArrayIndexOutOfBoundsException
i<=name.length
name.length
name
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
这就是在 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数组教程
在您的代码中,您已经访问了从索引 0 到字符串数组长度的元素。 给出字符串对象数组中的字符串对象数量,即 3,但您最多只能访问索引 2 ,
因为数组可以从索引 0 访问到您获取对象数的位置。name.length
name[2]
name.length - 1
name.length
即使在使用循环时,您也以索引 0 开头,并且应该以 .在数组 a[n] 中,您可以访问形式 a[0] 到 a[n-1]。for
name.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');
}
这个简单的问题就这么多,但我只想强调 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
当您尝试访问
不存在的 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
}
对于给定的数组,数组的长度为 3(即 name.length = 3)。但是由于它存储从索引 0 开始的元素,因此它的最大索引为 2。
因此,您应该写“i<**name.length”以避免“ArrayIndexOutOfBoundsException”,而不是“i**<=name.length”。
根据您的代码:
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');
}
ArrayIndexOutOfBoundsException
name 本身解释说,如果您尝试访问超出 Array size 范围的索引处的值,则会发生此类异常。
在您的例子中,您可以从 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].length
a[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'。我希望你能得到想法,谢谢!
每当出现此异常时,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]);
}
- 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);
如果使用数组的长度来控制 for 循环的迭代,请始终记住数组中第一项的索引为 0。因此,数组中最后一个元素的索引比数组的长度小 1。
您可以在函数样式中使用 Optional 来避免和:NullPointerException
ArrayIndexOutOfBoundsException
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
当您尝试访问不存在的数组的索引时,会发生 ArrayIdexOutOfBoundException。在 i = 3 的场景中,您尝试检索 names 数组的第 3 个索引。但是 names 数组最多保存第二个索引的值。
由于数组的第 3 个索引处没有值,因此会引发此异常。
评论
i <= name.length
i < name.length
for (String aName : name) { ... }
)