如何避免ArrayIndexOutOfBoundsException或IndexOutOfBoundsException?

-9 java arrays arraylist indexoutofboundsexception

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

这是关于这个主题的最全面的Canonical信息集合 java.lang.ArrayIndexOutOfBoundsException以及java.lang.IndexOutOfBoundsException.

有很多像这样的问题,所有这些都有模糊的没有代码答案,或者大多数都非常具体,并且局限于手头的问题,并没有解决在所有情况下完全相同的根本原因.


如果您看到属于此一般情况的一个,而不是使用更多重复的专门内容回答它,请将其标记为此副本的副本.

小智 6

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

JavaDoc中简略地指出:

抛出以指示已使用非法索引访问数组.索引为负数或大于或等于数组的大小.

是什么导致它发生?

此异常意味着您已尝试访问阵列或阵列支持列表中的索引,并且该索引不存在.

Java使用0基于索引.这意味着所有索引0都以第一个元素的索引开头,如果它包含任何元素.

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
Run Code Online (Sandbox Code Playgroud)

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

如何避免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));
Run Code Online (Sandbox Code Playgroud)

如果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;
    }
}
Run Code Online (Sandbox Code Playgroud)

迭代时:

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]);  
}
Run Code Online (Sandbox Code Playgroud)

使用增强的for/each循环:

如果您不需要知道实际索引,这是Array使用 增强的for循环迭代raw的惯用方法:

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

使用类型安全的迭代器:

这是Array使用增强的for循环遍历raw 并跟踪当前索引并避免遇到a的可能性的安全方法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());
}
Run Code Online (Sandbox Code Playgroud)

如果你不能使用番石榴或你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(); }
}
Run Code Online (Sandbox Code Playgroud)

并使用与Guava相同的代码.

如果您绝对必须拥有该项目的序数,则以下是最安全的方法.

// 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());
}
Run Code Online (Sandbox Code Playgroud)

这种技术适用于所有人Iterables,它不是一个indexperse,但它确实为你提供了迭代中的当前位置,即使对于没有本机的东西也是如此index.

最安全的方式:

最好的方法是始终使用Guava中的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());
}
Run Code Online (Sandbox Code Playgroud)

摘要:

  1. 使用原料Array很难使用,在大多数情况下应该避免使用.他们很容易受到微妙的一次性错误的影响,这些错误一直困扰着新的程序员甚至回到过去BASIC
  2. 现代Java习语使用适当的类型安全,CollectionsArray尽可能避免使用原始结构.
  3. Immutable 现在几乎在所有情况下都优选类型.
  4. Guava 是现代Java开发不可或缺的工具包.