是什么导致java.lang.ArrayIndexOutOfBoundsException以及如何防止它?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是什么导致java.lang.ArrayIndexOutOfBoundsException以及如何防止它?相关的知识,希望对你有一定的参考价值。
什么ArrayIndexOutOfBoundsException
意味着什么,我如何摆脱它?
以下是触发异常的代码示例:
String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
System.out.println(name[i]);
}
你的第一个停靠点应该是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循环,请执行此操作。)
由于ArrayIndexOutOfBoundsException
部分,你得到i<=name.length
。 name.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
可能是正数或零。
这就是在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
我见过看似神秘的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的同步部分。
确保代码中没有以并发方式访问线程不安全类(如SimpleDateFormat)的位置,例如在servlet或控制器中。检查servlet和控制器的所有实例变量以查找可能的嫌疑人。
对于多维数组,确保访问正确维度的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
)。
ArrayIndexOutOfBoundsException每当发生此异常时,它意味着您正在尝试使用超出其范围的数组索引,或者您正在请求超过初始化的非专业术语。
为了防止这种情况,请始终确保您没有请求数组中不存在的索引,即如果数组长度为10,则索引必须介于0到9之间
ArrayIndexOutOfBounds意味着您正在尝试索引未分配的数组中的位置。
在这种情况下:
String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
System.out.println(name[i]);
}
- name.length为3,因为已使用3个String对象定义了数组。
- 当访问数组的内容时,位置从0开始。由于有3个项目,它将表示名称[0] =“tom”,名称[1] =“dick”和名称[2] =“哈里
- 当你循环时,因为我可以小于或等于name.length,你试图访问不可用的名称[3]。
绕过这个......
- 在你的for循环中,你可以做<name.length。这将阻止循环到名称[3],而是停止在名称[2]
for(int i = 0; i<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);
ArrayIndexOutOfBoundsException
表示您正在尝试访问不存在或超出此数组范围的数组的索引。数组索引从0开始,以长度结束 - 1。
在你的情况下
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'
'); // i goes from 0 to length, Not correct
}
当您尝试访问不存在的name.length索引元素时,会发生ArrayIndexOutOfBoundsException
(数组索引以长度-1结尾)。只需用<替换<=就可以解决这个问题。
for(int i = 0; i < name.length; i++) {
System.out.print(name[i] +'
'); // i goes from 0 to length - 1, Correct
}
对于任何长度为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); }
根据您的准则:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'
');
}
如果检查System.out.print(name.length);
你会得到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] +'
');
}
数组中的每个项称为一个元素,每个元素都由其数字索引访问。如上图所示,编号从0开始。例如,第9个元素将在索引8处访问。
抛出IndexOutOfBoundsException以指示某种索引(例如数组,字符串或向量)超出范围。
任何数组X都可以从[0到(X.length - 1)]访问
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];
}
See also:
更新:根据您的代码段,
for (int i = 0; i<=name.length; i++) {
索引包含数组的长度。这是出界的。你需要用<=
替换<
。
for (int i = 0; i < name.length; i++) {
我在这里看到所有答案,解释了如何使用数组以及如何避免索引超出范围的异常。我个人不惜一切代价避免使用阵列。我使用Collections类,它避免了完全处理数组索引的所有愚蠢。循环结构可以很好地处理支持代码的集合,这些代码更易于编写,理解和维护。