Java 如何避免 ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32568261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:46:32  来源:igfitidea点击:

How to avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException?

javaarraysarraylistindexoutofboundsexception

提问by

If your question is I am getting a java.lang.ArrayIndexOutOfBoundsExceptionin my code and I do not understand why it is happening. What does it mean and how can I avoid it?

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

This is meant to be the most comprehensive Canonicalcollection of information on this java.lang.ArrayIndexOutOfBoundsExceptiontopic as well as the java.lang.IndexOutOfBoundsException.

这意味着是最全面的规范的信息采集对这个 java.lang.ArrayIndexOutOfBoundsException话题还有java.lang.IndexOutOfBoundsException

There are many questions like this and all of them have either vague no code answers, or mostly they are extremely specific and localized to the question at hand and do not address the root cause which is exactly the same in all cases.

有很多这样的问题,并且所有这些问题的答案要么含糊不清,要么大部分都是非常具体的,并且针对手头的问题进行了本地化,并且没有解决在所有情况下都完全相同的根本原因。



If you see one that falls under this general case, rather than answer it with more duplicate specialized content, mark it as a duplicate of this one.

如果您看到属于这种一般情况的内容,而不是用更多重复的专业内容来回答它,而是将其标记为此内容的副本。

采纳答案by

What is java.lang.ArrayIndexOutOfBoundsException / java.lang.IndexOutOfBoundsException?

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

The JavaDoccurtly states:

JavaDoc中简略地指出:

Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.

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

What causes it to happen?

是什么导致它发生?

This exception means that you have tried to access an index in an array or array backed list and that index does not exist.

Java uses 0based indexes. That means all indexes start with 0as the index of the first element if it contains any elements.

此异常意味着您尝试访问数组或数组支持列表中的索引,但该索引不存在。

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

The IndexOutOfBoundsExceptionmessage is very explicit, it usually takes the form of:

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

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

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

Where Indexis the index that you requested that does not exist and Sizeis the length of the structure you were indexing into.

Index您请求的不存在的索引在哪里,是您Size要索引到的结构的长度。

As you can see a Size: 1means the only valid index is 0and you were asking for what was at index 1.

正如您所看到的那样Size: 1,唯一有效的索引是0并且您正在询问 index 中的内容1

For example if you have an raw Arrayof objects or primitive types the valid indexes are 0to .length - 1, in the following example the valid indexes would be 0,1,2,3,.

例如,如果你有一个原始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

This also applies to ArrayListas well as any other Collectionclasses that may be backed by an Arrayand allow direct access to the the index.

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

How to avoid the java.lang.ArrayIndexOutOfBoundsException/ java.lang.IndexOutOfBoundsException?

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

When accessing directly by index:

通过索引直接访问时:

This uses Guavato convert the raw primitive int[]array to an ImmutableList<Integer>. Then it uses the Iterablesclass to safely get the value at a particular index and provides a default value when that index does not exist. Here I chose -1to indicate an invalid index value.

这使用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));

If you can't use Guavafor some reason it is easy to roll your own function to do this same thing.

如果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;
    }
}

When iterating:

迭代时:

Here is the idiomatic ways to iterate over a raw Arrayif you need to know the index and the value:

This is susceptible to one off errorswhich are the primary causes of an java.lang.ArrayIndexOutOfBoundsException:

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]);  
}

Using an enhanced for/each loop:

使用增强的 for/each 循环:

Here is the idiomatic way to iterate over a raw Arraywith the enhanced for loopif you do not need to know the actual index:

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

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

Using a type safe Iterator:

使用类型安全的迭代器:

Here is the safe way to iterate over a raw Arraywith the enhanced for loopand track the current index and avoids the possibility of encountering an java.lang.ArrayIndexOutOfBoundsException.

This uses Guava to easily convert the int[]to something Iterableevery project should include it.

这是Array使用增强的 for 循环迭代原始数据并跟踪当前索引并避免遇到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());
}

If you can not use Guava or your int[]is huge you can roll your own ImmutableIntArrayIteratoras such:

如果你不能使用番石榴或者你的番石榴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(); }
}

And use the same code as you would with Guava.

并使用与 Guava 相同的代码。

If you absolutely must have the ordinalof the item the following is the safest way to do it.

如果您绝对必须拥有项目的序号,那么以下是最安全的方法。

// 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());
}

This technique works for all Iterables, it is not an indexperse but it does give you the current position in the iteration even for things that do not have a native index.

这种技术适用于所有人Iterables,它不是一种index本质,但它确实为您提供了迭代中的当前位置,即使对于没有原生的事物index

The safest way:

最安全的方法:

The best way is to always use ImmutableLists/Set/Mapsfrom Guava as well:

最好的方法是始终使用来自 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());
}

Summary:

概括:

  1. Using raw Arrayare difficult to work with and should be avoided in most cases. They are susceptible to sometimes subtle one off errorswhich have plague new programmers even back to the days of BASIC
  2. Modern Java idioms use proper type safe Collectionsand avoid using raw Arraystructures if at all possible.
  3. Immutabletypes are preferred in almost all cases now.
  4. Guavais an indispensable toolkit for modern Java development.
  1. 使用 rawArray很难处理,在大多数情况下应该避免使用。他们有时很容易受到微妙的一次性错误的影响,这些错误甚至可以追溯到程序员的时代。BASIC
  2. 现代 Java 习语使用适当的类型安全,CollectionsArray尽可能避免使用原始结构。
  3. Immutable现在几乎在所有情况下都首选类型。
  4. Guava是现代Java开发不可或缺的工具包。

回答by g5thomas

Referring to the Java documentation Class ArrayIndexOutOfBoundsException, this exception is thrown when you try to access an element that is either negative, or greater than the size of the Array.

参考 Java 文档Class ArrayIndexOutOfBoundsException,当您尝试访问一个为负数或大于 Array 大小的元素时,会抛出此异常。

Consider the case you have 10 items in the array. You can ask the system what is the first to the tenth item within the array. If you try to ask what is the -1 item or the 100th item in the array, Java would response with the above exception. Now keep in mind that Array in Java is 0 indexed. Therefore, you can only pass an index value of 0 to 9 inclusive. Any number not in this range will throws the specific error mentioned above.

考虑数组中有 10 个项目的情况。您可以询问系统数组中的第一个到第十个项目是什么。如果您尝试询问数组中的 -1 项或第 100 项是什么,Java 将响应上述异常。现在请记住,Java 中的 Array 是 0 索引的。因此,您只能传递 0 到 9 之间的索引值。任何不在此范围内的数字都会引发上述特定错误。

To avoid this exception, let's go back to the concept of CS101, and review the concept of loop invariant. This is a condition to make sure that the variable you use to store the index must be meet the particular condition.

为了避免这个异常,让我们回到 CS101 的概念,回顾一下循环不变量的概念。这是确保用于存储索引的变量必须满足特定条件的条件。

Here is a link to loop invariant: wikipedia > Loop invariant

这是循环不变式的链接:维基百科 > 循环不变式