是什么ArrayIndexOutOfBoundsException
意思,我该如何摆脱它?
这是触发异常的代码示例:
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
System.out.println(names[i]);
}
您的第一个停靠港应该是合理清楚地解释它的文档:
抛出以指示已使用非法索引访问数组。索引为负数或大于或等于数组的大小。
例如:
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 in for loop
简单地说:
在最后一次迭代中
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];
什么原因ArrayIndexOutOfBoundsException
?
如果您将变量视为可以放置值的“盒子”,那么数组就是彼此相邻放置的一系列盒子,其中盒子的数量是有限且明确的整数。
像这样创建一个数组:
final int[] myArray = new int[5]
创建一排 5 个盒子,每个盒子都有一个int
. 每个盒子都有一个索引,即在一系列盒子中的位置。该索引从 0 开始,到 N-1 结束,其中 N 是数组的大小(框的数量)。
要从这一系列框中检索其中一个值,您可以通过其索引来引用它,如下所示:
myArray[3]
这将为您提供系列中第 4 个框的值(因为第一个框的索引为 0)。
AnArrayIndexOutOfBoundsException
是由于试图检索一个不存在的“盒子”,通过传递一个高于最后一个“盒子”的索引或负数的索引而引起的。
在我运行的示例中,这些代码片段会产生这样的异常:
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) {
这样你就不必考虑索引了。
循环时,无论您做什么,都不要更改循环迭代器的值(此处: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];
}
为避免数组索引越界异常,应在可以使用的地方和时间使用增强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");
}
在您的代码中,您访问了从索引 0 到字符串数组长度的元素。name.length
给出字符串对象数组中的字符串对象数,即 3,但您最多只能访问索引 2 name[2]
,因为可以从索引 0 访问数组,直到name.length - 1
您获得name.length
对象数的位置。
即使在使用for
循环时,您也从索引零开始,您应该以name.length - 1
. 在数组 a[n] 中,您可以从 a[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');
}
对于您给定的数组,数组的长度为 3(即 name.length = 3)。但由于它存储从索引 0 开始的元素,因此它的最大索引为 2。
所以,你应该写 'i <**name.length'而不是 'i**<= name.length ' 以避免出现 'ArrayIndexOutOfBoundsException'。
这个简单的问题就这么多,但我只想强调 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
了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] +'\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 的整数:超出范围;
PS:如果您希望对数组有更好的理解并进行一些实际练习,这里有一个视频:Java 数组教程
对于多维数组,确保访问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
,为简单起见)。
我见过的看似神秘的 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 和控制器的所有实例变量以查找可能的嫌疑人。
对于任何长度为 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 each 循环,在这种方法中,程序员无需担心数组中元素的数量。
for(String str : array) {
System.out.println(str);
}
ArrayIndexOutOfBoundsException 每当出现此异常时,这意味着您正在尝试使用超出其范围的数组索引,或者用外行术语来说,您请求的数量超过了您的初始化。
为了防止这种情况,请始终确保您没有请求数组中不存在的索引,即如果数组长度为 10,那么您的索引必须在 0 到 9 之间
ArrayIndexOutOfBounds 意味着您正在尝试索引未分配的数组中的位置。
在这种情况下:
String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
System.out.println(name[i]);
}
为了解决这个...
在您的 for 循环中,您可以执行 i < name.length。这将防止循环到 name[3],而是在 name[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] +'\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
}
根据您的代码:
String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
System.out.print(name[i] +'\n');
}
如果您检查 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] +'\n');
}
数组中的每一项都称为一个元素,每个元素都通过其数字索引访问。如上图所示,编号以 0 开头。例如,第 9 个元素将在索引 8 处访问。
抛出 IndexOutOfBoundsException 以指示某种索引(例如数组、字符串或向量)超出范围。
任何数组 X,可以从 [0 到 (X.length - 1)] 访问
我在这里看到了所有答案,解释了如何使用数组以及如何避免索引越界异常。我个人不惜一切代价避免使用数组。我使用 Collections 类,它避免了必须完全处理数组索引的所有愚蠢。循环结构与支持更易于编写、理解和维护的代码的集合完美配合。
如果您使用数组的长度来控制for循环的迭代,请始终记住数组中第一项的索引是0。所以数组中最后一个元素的索引比数组的长度小一。
ArrayIndexOutOfBoundsException
名称本身解释说,如果您尝试访问超出数组大小范围的索引处的值,则会发生此类异常。
在您的情况下,您可以从 for 循环中删除等号。
for(int i = 0; i<name.length; i++)
更好的选择是迭代一个数组:
for(String i : name )
System.out.println(i);
此错误发生在运行循环超限时间。让我们考虑这样的简单示例,
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.长度-2),数组的最后一个元素被打印。当'i'值变为(numberArray.length-1)时,没有打印值..在那一点,'ArrayIndexOutOfBoundsException'发生。我希望你能得到想法。谢谢!
您可以在功能样式中使用 Optional 来避免NullPointerException
and 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
在大多数编程语言中,索引都是从 0 开始的。所以你必须写i<names.length或i<=names.length-1而不是i<=names.length。
您不能迭代或存储超过数组长度的数据。在这种情况下,您可以这样做:
for (int i = 0; i <= name.length - 1; i++) {
// ....
}
或这个:
for (int i = 0; i < name.length; i++) {
// ...
}