Вопрос-ответ

How can I avoid ArrayIndexOutOfBoundsException or IndexOutOfBoundsException? [duplicate]

Как я могу избежать ArrayIndexOutOfBoundsException или IndexOutOfBoundsException?

Если ваш вопрос в том, что я получаю java.lang.ArrayIndexOutOfBoundsException в своем коде и не понимаю, почему это происходит, что это значит и как я могу этого избежать?


Предполагается, что это наиболее полный канонический сборник информации по этой java.lang.ArrayIndexOutOfBoundsException теме, а также по java.lang.IndexOutOfBoundsException.


Подобных вопросов много, и все они либо содержат расплывчатые ответы без кода, либо в основном они чрезвычайно конкретны и локализованы под рассматриваемый вопрос и не устраняют основную причину, которая во всех случаях абсолютно одинакова.



Если вы видите исключение, которое подпадает под этот общий случай, вместо того, чтобы отвечать на него более повторяющимся специализированным контентом, пометьте его как дубликат этого.


Переведено автоматически
Ответ 1

Что такое 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 to .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 а также к любым другим 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));

Если вы по какой-то причине не можете использовать 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;
}
}

При повторении:


Вот идиоматические способы перебора raw 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]);
}

Использование расширенного цикла для каждого:


Вот идиоматический способ выполнить итерацию по raw Array с помощью расширенного цикла for, если вам не нужно знать фактический индекс:


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

Использование типобезопасного итератора<T>:


Вот безопасный способ выполнить итерацию по raw 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());
}

Если вы не можете использовать Guava или ваш 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(); }
}

И используйте тот же код, что и в случае с 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());
}

Этот метод работает для всех итерируемых объектов. Это не синтаксический анализ с индексом, но он дает вам текущую позицию в итерации даже для объектов, у которых нет собственного индекса.

Самый безопасный способ:


Лучший способ - всегда использовать ImmutableLists/ Set /Maps также из Guava:


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. С использованием необработанных массивов сложно работать, и в большинстве случаев их следует избегать. Они подвержены иногда незначительным разовым ошибкам, которые преследовали начинающих программистов еще во времена BASIC



  2. Современные идиомы Java используют надлежащие типобезопасные коллекции и избегают использования необработанных структур массивов, если это вообще возможно.



  3. Неизменяемые типы теперь предпочтительны почти во всех случаях.



  4. Guava - незаменимый инструментарий для современной разработки на Java.



Ответ 2

Ссылаясь на документацию Java для класса ArrayIndexOutOfBoundsException, это исключение выдается при попытке получить доступ к элементу, который либо отрицательный, либо превышает размер массива.

Рассмотрим случай, когда у вас в массиве 10 элементов. Вы можете запросить у системы с первого по десятый элемент в массиве. Если вы попытаетесь запросить элемент -1 или 100-й элемент в массиве, Java ответит приведенным выше исключением.

Теперь имейте в виду, что массив в Java основан на нуле. Следовательно, вы можете передавать значение индекса только от 0 до 9 включительно. Любое число, не входящее в этот диапазон, вызовет конкретную ошибку, упомянутую выше.

Чтобы избежать этого исключения, давайте вернемся к концепции информатики 101 и рассмотрим концепцию инварианта цикла. Это условие, позволяющее убедиться, что переменная, которую вы используете для хранения индекса, должна соответствовать определенному условию.

java arrays arraylist