我如何避免ArrayIndexOutOf边界异常或IndexOutOf边界异常?
如果您的问题是我的代码中出现java.lang.ArrayIndexOutOfBoundsException
,而我不明白为什么会发生这种情况,它意味着什么,我如何才能避免它?
这是最全面的canonical信息收集java.lang.ArrayIndexOutOfBoundsException
主题以及java.lang.IndexOutOfBoundsException
。
类似的问题有很多,而且所有问题都有模糊的无代码答案,或者大多数问题都非常具体和局限于手头的问题,没有解决在所有情况下都完全相同的根本原因。
如果您看到属于此一般情况的案例,而不是使用更多重复的专业内容来回答它,请将其标记为此案例的副本。
解决方案
什么是java.lang.ArrayIndexOutOf边界异常/java.lang.IndexOutOf边界异常?
JavaDoc简略说明:
抛出以指示已使用非法的 索引。索引为负值或大于或等于 数组的大小。
发生这种情况的原因是什么?
此异常表示您试图访问 数组或数组支持的列表,并且该索引不存在。 Java使用基于0
的索引。这意味着所有索引都以0
AS开头 第一个元素的索引(如果它包含任何元素)。
IndexOutOfBoundsException
消息非常明确,通常采用以下形式:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
其中Index
是您请求的不存在的索引,Size
是要索引到的结构的长度。
如您所见,Size: 1
表示唯一有效的索引是0
,您要求的是索引1
处的内容。
例如,如果您有对象或基元类型的原始Array
有效索引是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
类来安全地 获取特定索引处的值,并在以下情况下提供默认值 该索引不存在。在这里,我选择-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,则可以轻松地滚动您自己的函数来执行相同的操作。
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循环:
以下是使用以下命令迭代原始Array
的惯用方法
如果不需要知道实际索引,则增强FOR循环:
for (final int i : ints)
{
System.out.format("%d", i);
System.out.println();
}
使用类型安全迭代器<;T>;:
下面是使用增强的迭代原始Array
的安全方法 for循环并跟踪当前索引,避免 遇到java.lang.ArrayIndexOutOfBoundsException
。 这使用芭乐轻松地将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());
}
此技术适用于所有迭代。它不是索引分析,但它确实为您提供迭代中的当前位置,即使对于没有本机索引的内容也是如此。
最安全的方式:
最好的方法是始终使用来自番石榴的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());
}
摘要:
使用原始数组很难使用,在大多数情况下应该避免使用。它们很容易受到有时微妙的one-off errors的影响,这甚至可以追溯到BASIC
的日子现代Java习惯用法使用正确的类型安全集合,并尽可能避免使用原始数组结构。
现在几乎所有情况下都首选不可变类型。
Guava是现代Java开发不可或缺的工具包。
相关文章