如何避免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()); }
概要:
- 使用原始
Array
很难处理,在大多数情况下应该避免。 它们容易出现一些微妙的错误 ,这些错误使新程序员甚至回到了BASIC
- 现代Java成语使用适当types的安全
Collections
并尽可能避免使用原始Array
结构。 - 现在几乎所有情况下,
Immutable
types都是首选。 -
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
- Java:如何读取文本文件
- Java:检测ArrayList中的重复项?
- ArrayIndexOutOfBoundsException在使用ArrayList的迭代器时
- ArrayList.clear()和ArrayList.removeAll()有什么区别?
- 使用自定义sorting顺序对对象的ArrayList进行sorting
- Java中的ArrayList或List声明
- 在ArrayList中使用自定义对象来search特定的string
- ArrayList <String>到CharSequence
- 在ArrayList上操作时,AbstractList.remove()中的UnsupportedOperationException