如何避免ArrayIndexOutOfBoundsException或IndexOutOfBoundsException?

如果你的问题是我在我的代码中得到一个java.lang.ArrayIndexOutOfBoundsException ,我不明白为什么它发生。 这是什么意思,我该如何避免呢?

这意味着要成为关于这个java.lang.ArrayIndexOutOfBoundsException主题以及java.lang.ArrayIndexOutOfBoundsException的最全面的Canonical信息集合。

这样的问题很多,都是模糊的,没有代码的答案,或者大都是非常具体的,本地化的问题,并没有解决在所有情况下都是完全一样的根本原因。


如果你看到一个属于这个一般情况的东西,而不是用更多重复的专门内容回答它,把它标记为这个东西的一个重复。

什么是java.lang.ArrayIndexOutOfBoundsException / java.lang.IndexOutOfBoundsException?

JavaDoc简要说明:

抛出以指示已经使用非法索引访问数组。 该索引是否定的或者大于或等于数组的大小。

是什么导致它发生?

此exception意味着您已尝试访问arrays或arrays支持列表中的索引,并且该索引不存在。

Java使用基于0的索引。 这意味着如果所有索引包含任何元素,则所有索引都以0作为第一个元素的索引。

IndexOutOfBoundsException消息非常明确,通常采用以下forms:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

其中Index是您所请求的不存在的索引, Size是您索引到的结构的长度。

正如你可以看到一个Size: 1意味着唯一有效的索引是0 ,你问索引1是什么。

例如,如果您有一个原始的对象Array或原始types,则有效索引为0.length - 1 ,在以下示例中,有效索引将为0,1,2,3,

 final String days[] { "Sunday", "Monday", "Tuesday" } System.out.println(days.length); // 3 System.out.println(days[0]); // Sunday System.out.println(days[1]); // Monday System.out.println(days[2]); // Tuesday System.out.println(days[3]); // java.lang.ArrayIndexOutOfBoundsException 

这也适用于ArrayList以及任何其他可以由Array支持并允许直接访问索引的Collection类。

如何避免java.lang.ArrayIndexOutOfBoundsException / java.lang.IndexOutOfBoundsException

当通过索引直接访问时:

这使用Guava将原始的int[]数组转换为ImmutableList<Integer> 。 然后它使用Iterables类安全地获取特定索引的值,并在该索引不存在时提供默认值。 这里我select-1来表示一个无效的索引值。

 final List<Integer> toTen = ImmutableList.copyOf(Ints.asList(ints)); System.out.println(Iterables.get(toTen, 0, -1)); System.out.println(Iterables.get(toTen, 100, -1)); 

如果因为某些原因不能使用Guava ,那么很容易就可以将自己的function做到这一点。

 private static <T> T get(@Nonnull final Iterable<T> iterable, final int index, @Nonnull final T missing) { if (index < 0) { return missing; } if (iterable instanceof List) { final List<T> l = List.class.cast(iterable); return l.size() <= index ? l.get(index) : missing; } else { final Iterator<T> iterator = iterable.iterator(); for (int i = 0; iterator.hasNext(); i++) { final T o = iterator.next(); if (i == index) { return o; } } return missing; } } 

迭代时:

如果你需要知道索引和值,下面是迭代原始Array方法:

这容易造成一个错误 ,这是java.lang.ArrayIndexOutOfBoundsException主要原因:

使用传统的for / next循环:

 final int ints[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; for (int i = 0; i < ints.length; i++) { System.out.format("index %d = %d", i, ints[i]); } 

使用增强的for / each循环:

如果你不需要知道实际的索引,下面是使用增强的for循环迭代原始Array方法:

 for (final int i : ints) { System.out.format("%d", i); System.out.println(); } 

使用types安全的迭代器:

以下是使用增强for循环迭代原始Array的安全方法,并跟踪当前索引,并避免遇到java.lang.ArrayIndexOutOfBoundsException

这使用Guava轻松地将int[]转换为每个项目都应该包含的Iterable

 final Iterator<Integer> it = Ints.asList(ints).iterator(); for (int i = 0; it.hasNext(); i++) { System.out.format("index %d = %d", i, it.next()); } 

如果你不能使用番石榴或你的int[]是巨大的,你可以推出你自己的ImmutableIntArrayIterator

 public class ImmutableIntArrayIterator implements Iterator<Integer> { private final int[] ba; private int currentIndex; public ImmutableIntArrayIterator(@Nonnull final int[] ba) { this.ba = ba; if (this.ba.length > 0) { this.currentIndex = 0; } else { currentIndex = -1; } } @Override public boolean hasNext() { return this.currentIndex >= 0 && this.currentIndex + 1 < this.ba.length; } @Override public Integer next() { this.currentIndex++; return this.ba[this.currentIndex]; } @Override public void remove() { throw new UnsupportedOperationException(); } } 

和使用番石榴一样使用相同的代码。

如果你绝对必须有这个项目的序号 ,以下是最安全的方法来做到这一点。

 // assume los is a list of Strings final Iterator<String> it = los.iterator(); for (int i = 0; it.hasNext(); i++) { System.out.format("index %d = %s", i, it.next()); } 

这个技巧适用于所有的Iterables ,它不是一个index持久化,但它确实给你在迭代中的当前位置,即使是没有本地index

最安全的方式:

最好的方法是始终使用来自番石榴的ImmutableLists / Set / Maps :

 final List<Integer> ili = ImmutableList.copyOf(Ints.asList(ints)); final Iterator<Integer> iit = ili.iterator(); for (int i = 0; iit.hasNext(); i++) { System.out.format("index %d = %d", i, iit.next()); } 

概要:

  1. 使用原始Array很难处理,在大多数情况下应该避免。 它们容易出现一些微妙的错误 ,这些错误使新程序员甚至回到了BASIC
  2. 现代Java成语使用适当types的安全Collections并尽可能避免使用原始Array结构。
  3. 现在几乎所有情况下, Immutabletypes都是首选。
  4. Guava是现代Java开发不可或缺的工具包。

参考Java文档https://docs.oracle.com/javase/7/docs/api/java/lang/ArrayIndexOutOfBoundsException.html ,当您尝试访问负值或大于Array的大小。

考虑一下你在数组中有10个项目的情况。 您可以询问系统中第一个到第十个项目是什么。 如果您试图询问数组中的-1项或第100项,Java将以上述exception作为响应。 现在请记住,在Java中的数组是0索引。 因此,只能传递0到9的索引值。 任何不在这个范围内的数字都会抛出上面提到的具体错误。

为了避免这个例外,我们回到CS101的概念,并回顾循环不变的概念。 这是确保用于存储索引的variables必须满足特定条件的条件。

这是一个链接到循环不变https://en.wikipedia.org/wiki/Loop_invariant