Что вызывает исключение java.lang.ArrayIndexOutOfBoundsException и как его предотвратить?

298

Что ArrayIndexOutOfBoundsExceptionзначит и как от этого избавиться?

Вот пример кода, который вызывает исключение:

String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
    System.out.println(names[i]);
}
Аарон
источник
1
Что касается последнего вопроса, код будет полезным. Вы обращаетесь к массиву с известным индексом, или вам нужно начать отладку, чтобы выяснить, как рассчитывается индекс при возникновении ошибки?
Юсткт
43
Замените i <= name.lengthна i < name.length- или лучше, напишите расширенный цикл for. ( for (String aName : name) { ... })
Жан Гоминал
1
это означает, что вы хотите получить элемент массива, который не существует, 'i <= name.length' означает, что вы хотите получить длину элемента + 1 - его не существует.
gbk
Смотрите ArrayIndexOutOfBounds для цикла .
aioobe

Ответы:

297

Ваш первый порт захода должен быть документацией, которая объясняет это достаточно ясно:

Брошенный, чтобы указать, что к массиву обращались с недопустимым индексом. Индекс либо отрицательный, либо больше или равен размеру массива.

Так, например:

int[] array = new int[5];
int boom = array[10]; // Throws the exception

Что касается того, как этого избежать ... не делай этого. Будьте осторожны с вашими индексами массива.

Одна проблема, с которой иногда сталкиваются люди, - это думать, что массивы индексируются 1, например

int[] array = new int[5];
// ... populate the array here ...
for (int index = 1; index <= array.length; index++)
{
    System.out.println(array[index]);
}

Это упустит первый элемент (индекс 0) и выдаст исключение, когда индекс равен 5. Допустимые индексы здесь 0-4 включительно. Правильное идиоматическое forутверждение здесь будет следующим:

for (int index = 0; index < array.length; index++)

( Конечно , при условии, что вам нужен индекс. Если вы можете использовать вместо этого расширенный цикл for, сделайте это.)

Джон Скит
источник
1
Я хотел бы добавить , что для многомерных массивов , которые могут иметь произвольную форму в Java, вложенные циклы должны проверить для соответствующей длины подмассива: for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }.
Андрей
52
if (index < 0 || index >= array.length) {
    // Don't use this index. This is out of bounds (borders, limits, whatever).
} else {
    // Yes, you can safely use this index. The index is present in the array.
    Object element = array[index];
}

Смотрите также:


Обновление : согласно вашему фрагменту кода,

for (int i = 0; i<=name.length; i++) {

Индекс включает длину массива. Это за пределами. Вам нужно заменить <=на <.

for (int i = 0; i < name.length; i++) {
BalusC
источник
22

Из этой превосходной статьи: ArrayIndexOutOfBoundsException в цикле for

Короче говоря:

В последней итерации

for (int i = 0; i <= name.length; i++) {

iбудет равно name.lengthнедопустимому индексу, так как индексы массива начинаются с нуля.

Ваш код должен читать

for (int i = 0; i < name.length; i++) 
                  ^
aioobe
источник
17

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

Например, это инициализирует примитивный массив целых чисел с верхней границей 4.

int intArray[] = new int[5];

Программисты считают с нуля. Так что это, например, бросило бы ArrayIndexOutOfBoundsExceptionкак верхняя граница 4, а не 5.

intArray[5];
Октавиан А. Дамиан
источник
4
Границы - это пределы в пределах диапазона. то есть; 0-5
Джон Джотта
11

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

Основная мотивация (и вариант использования) - это когда вы выполняете итерацию, и вам не требуются какие-либо сложные шаги итерации. Вы не сможете использовать расширенныйfor для перемещения назад в массиве или только для итерации по каждому другому элементу.

При этом вы гарантированно не исчерпаете элементы для повторения, и ваш [исправленный] пример легко преобразуется.

Код ниже:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i< name.length; i++) {
    System.out.print(name[i] + "\n");
}

... эквивалентно этому:

String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
    System.out.println(firstName + "\n");
}
Makoto
источник
11

Что вызывает ArrayIndexOutOfBoundsException?

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

Создание массива, как это:

final int[] myArray = new int[5]

создает ряд из 5 ящиков, каждый из которых содержит int. У каждого из ящиков есть индекс, позиция в ряду ящиков. Этот индекс начинается с 0 и заканчивается в N-1, где N - размер массива (количество блоков).

Чтобы извлечь одно из значений из этой серии блоков, вы можете обратиться к нему через его индекс, например:

myArray[3]

Что даст вам значение 4-го блока в серии (так как первый блок имеет индекс 0).

ArrayIndexOutOfBoundsExceptionВызывается пытается retrive «ящик» , который не существует, путем передачи индекса , который выше , чем показатель прошлого «коробки», или отрицательным.

В моем работающем примере эти фрагменты кода выдают такое исключение:

myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //waay to high

Как избежать ArrayIndexOutOfBoundsException

Для предотвращения ArrayIndexOutOfBoundsExceptionесть несколько ключевых моментов, которые следует учитывать:

перекручивание

При циклическом просмотре массива всегда проверяйте, что индекс, который вы получаете, строго меньше, чем длина массива (количество блоков). Например:

for (int i = 0; i < myArray.length; i++) {

Обратите внимание <, никогда не смешивайте =там ..

Вы можете захотеть сделать что-то вроде этого:

for (int i = 1; i <= myArray.length; i++) {
    final int someint = myArray[i - 1]

Просто не надо. Придерживайтесь приведенного выше (если вам нужно использовать указатель), и это избавит вас от боли.

Где возможно, используйте foreach:

for (int value : myArray) {

Таким образом, вам не придется думать об индексах вообще.

При выполнении цикла, что бы вы ни делали, НИКОГДА не меняйте значение итератора цикла (здесь:) i. Единственное место, где это должно изменить значение, это поддерживать цикл. В противном случае это просто риск исключения, и в большинстве случаев это не обязательно.

Извлечение / обновление

При извлечении произвольного элемента массива всегда проверяйте, является ли он допустимым индексом по длине массива:

public Integer getArrayElement(final int index) {
    if (index < 0 || index >= myArray.length) {
        return null; //although I would much prefer an actual exception being thrown when this happens.
    }
    return myArray[index];
}
TOBB
источник
6

В вашем коде вы получили доступ к элементам от индекса 0 до длины массива строк. name.lengthдает число строковых объектов в вашем массиве строковых объектов, то есть 3, но вы можете получить доступ только до индекса 2 name[2], потому что к массиву можно получить доступ от индекса 0 до того места, name.length - 1где вы получаете name.lengthколичество объектов.

Даже при использовании forцикла вы начали с индекса ноль, и вы должны закончить с name.length - 1. В массиве a [n] вы можете получить доступ от формы [0] к [n-1].

Например:

String[] a={"str1", "str2", "str3" ..., "strn"};

for(int i=0;i<a.length()i++)
    System.out.println(a[i]);

В твоем случае:

String[] name = {"tom", "dick", "harry"};

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'\n');
}
Мадхусудский шоудар
источник
5

Для вашего данного массива длина массива равна 3 (то есть name.length = 3). Но поскольку он хранит элемент, начиная с индекса 0, он имеет максимальный индекс 2.

Таким образом, вместо «i ** <= name.length» вы должны написать «i <** name.length», чтобы избежать «ArrayIndexOutOfBoundsException».

Нихилу
источник
3

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

int[] array = new int[5];

//If you need just the items
Arrays.stream(array).forEach(item -> { println(item); });

//If you need the index as well
IntStream.range(0, array.length).forEach(index -> { println(array[index]); })

В чем выгода? Ну, одна вещь - это удобочитаемость, как на английском. Во-вторых, вам не нужно беспокоиться оArrayIndexOutOfBoundsException

Сатьендра Кумар
источник
3

Вы получаете ArrayIndexOutOfBoundsExceptionиз-за i<=name.lengthчасти. name.lengthвернуть длину строки name, которая равна 3. Следовательно, когда вы пытаетесь получить доступ name[3], это недопустимо и выдает исключение.

Разрешенный код:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i < name.length; i++) { //use < insteadof <=
  System.out.print(name[i] +'\n');
}

Это определено в спецификации языка Java :

public finalПоле length, которое содержит число компонентов массива. lengthможет быть положительным или нулевым.

roottraveller
источник
3

Исключение индекса массива за пределами границ

Вот как выглядит этот тип исключения, когда выдается в Eclipse. Цифра красного цвета обозначает индекс, к которому вы пытались получить доступ. Таким образом, код будет выглядеть так:

myArray[5]

Ошибка выдается при попытке доступа к индексу, который не существует в этом массиве. Если массив имеет длину 3,

int[] intArray = new int[3];

тогда единственные допустимые индексы:

intArray[0]
intArray[1]
intArray[2]

Если массив имеет длину 1,

int[] intArray = new int[1];

тогда единственный действительный индекс:

intArray[0]

Любое целое число, равное длине массива или больше его: выходит за пределы.

Любое целое число меньше 0: выходит за пределы;

PS: Если вы хотите лучше понять массивы и выполнить некоторые практические упражнения, здесь есть видео: учебник по массивам в Java

Johny
источник
3

Для многомерных массивов может быть сложно получить доступ к lengthсвойству нужного измерения. Возьмите следующий код для примера:

int [][][] a  = new int [2][3][4];

for(int i = 0; i < a.length; i++){
    for(int j = 0; j < a[i].length; j++){
        for(int k = 0; k < a[j].length; k++){
            System.out.print(a[i][j][k]);
        }
        System.out.println();
    }
    System.out.println();
}

Каждое измерение имеет различную длину, поэтому тонкая ошибка заключается в том, что средний и внутренний циклы используют lengthсвойство одного и того же измерения (поскольку a[i].lengthоно совпадает с a[j].length).

Вместо этого следует использовать внутренний цикл a[i][j].length(или a[0][0].length, для простоты).

Билл Ящерица
источник
Добавлен пример кода из Почему цикл for не работает, когда я изменяю условие (многомерные массивы)? поскольку этот вопрос используется в качестве целевой цели для любого вопроса, касающегося ArrayIndexOutOfBoundsException.
Билл Ящерица
2

Наиболее распространенный случай, который я видел для, казалось бы, загадочных ArrayIndexOutOfBoundsExceptions, то есть, по-видимому, не вызванных вашим собственным кодом обработки массивов, - это одновременное использование SimpleDateFormat. Особенно в сервлете или контроллере:

public class MyController {
  SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");

  public void handleRequest(ServletRequest req, ServletResponse res) {
    Date date = dateFormat.parse(req.getParameter("date"));
  }
}

Если два потока введут метод SimplateDateFormat.parse () вместе, вы, скорее всего, увидите исключение ArrayIndexOutOfBoundsException. Обратите внимание на раздел синхронизации класса Javadoc для SimpleDateFormat .

Убедитесь, что в вашем коде нет места для одновременного доступа к небезопасным классам, таким как SimpleDateFormat, как в сервлете или контроллере. Проверьте все переменные экземпляра ваших сервлетов и контроллеров на наличие возможных подозреваемых.

Кири Сарантакос
источник
2

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

Чтобы предотвратить это, всегда убедитесь, что вы не запрашиваете индекс, которого нет в массиве, т.е. если длина массива равна 10, тогда ваш индекс должен находиться в диапазоне от 0 до 9

sgrpwr
источник
2

ArrayIndexOutOfBounds означает, что вы пытаетесь индексировать позицию в массиве, который не выделен.

В таком случае:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length равен 3, так как массив был определен с 3 объектами String.
  • При доступе к содержимому массива позиция начинается с 0. Так как есть 3 элемента, это будет означать name [0] = "tom", name [1] = "dick" и name [2] = "harry
  • Когда вы зацикливаетесь, поскольку я могу быть меньше или равен name.length, вы пытаетесь получить доступ к имени [3], которое недоступно.

Чтобы обойти это ...

  • В вашем цикле for вы можете сделать i <name.length. Это предотвратит зацикливание на имени [3] и остановит на имени [2]

    for(int i = 0; i<name.length; i++)

  • Используйте для каждого цикла

    String[] name = { "tom", "dick", "harry" }; for(String n : name) { System.out.println(n); }

  • Используйте list.forEach (Consumer action) (требуется Java8)

    String[] name = { "tom", "dick", "harry" }; Arrays.asList(name).forEach(System.out::println);

  • Конвертировать массив в поток - это хороший вариант, если вы хотите выполнить дополнительные «операции» с вашим массивом, например, фильтровать, преобразовывать текст, конвертировать в карту и т. Д. (Требуется Java8)

    String[] name = { "tom", "dick", "harry" }; --- Arrays.asList(name).stream().forEach(System.out::println); --- Stream.of(name).forEach(System.out::println);

martinywwan
источник
1

ArrayIndexOutOfBoundsExceptionозначает, что вы пытаетесь получить доступ к индексу массива, который не существует или находится за пределами этого массива. Индексы массива начинаются с 0 и заканчиваются длиной - 1 .

В твоем случае

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'\n'); // i goes from 0 to length, Not correct
}

ArrayIndexOutOfBoundsExceptionпроисходит, когда вы пытаетесь получить доступ к индексируемому элементу name.length, который не существует (индекс массива заканчивается длиной -1). просто замена <= на <решит эту проблему.

for(int i = 0; i < name.length; i++) {
    System.out.print(name[i] +'\n');  // i goes from 0 to length - 1, Correct
}
adn.911
источник
1

Для любого массива длины n элементы массива будут иметь индекс от 0 до n-1.

Если ваша программа пытается получить доступ к любому элементу (или памяти) с индексом массива, превышающим n-1, Java выдаст исключение ArrayIndexOutOfBoundsException

Итак, вот два решения, которые мы можем использовать в программе

  1. Ведение счета:

    for(int count = 0; count < array.length; count++) {
        System.out.println(array[count]);
    }

    Или какое-то другое зацикливание

    int count = 0;
    while(count < array.length) {
        System.out.println(array[count]);
        count++;
    }
  2. Лучший способ - использовать цикл для каждого цикла, в этом методе программисту не нужно беспокоиться о количестве элементов в массиве.

    for(String str : array) {
        System.out.println(str);
    }
Мохит
источник
1

Согласно вашему Кодексу:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
  System.out.print(name[i] +'\n');
}

Если вы проверяете System.out.print (name.length);

вы получите 3;

это означает, что ваше имя длина 3

Ваш цикл работает от 0 до 3, который должен быть либо "0 до 2", либо "1 до 3"

Ответ

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
  System.out.print(name[i] +'\n');
}
Абхишек Агарвал
источник
1

Каждый элемент в массиве называется элементом, и каждый элемент доступен по его числовому индексу. Как показано на предыдущем рисунке, нумерация начинается с 0 . Таким образом, к 9-му элементу, например, будет осуществляться доступ по индексу 8.

Выдается исключение IndexOutOfBoundsException, указывающее, что какой-то индекс (например, массив, строка или вектор) выходит за пределы допустимого диапазона.

Доступ к любому массиву X возможен от [0 до (X.length - 1)]

ZiadM
источник
1

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

Джон Чуккерманн
источник
1

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

Сачитра Дилшан
источник
0

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

В вашем случае вы можете просто удалить знак равенства из цикла for.

for(int i = 0; i<name.length; i++)

Лучший вариант - итерировать массив:

for(String i : name )
      System.out.println(i);
Мадхусудан Шарма
источник
0

Эта ошибка возникает при превышении лимита цикла выполнения. Давайте рассмотрим простой пример, подобный этому,

class demo{
  public static void main(String a[]){

    int[] numberArray={4,8,2,3,89,5};

    int i;

    for(i=0;i<numberArray.length;i++){
        System.out.print(numberArray[i+1]+"  ");
    }
}

Сначала я инициализировал массив как numberArray. затем некоторые элементы массива печатаются с использованием цикла for. Когда цикл выполняется время 'i', выведите элемент (numberArray [i + 1] .. (когда значение i равно 1, элемент numberArray [i + 1] напечатан.) .. Предположим, что когда i = (numberArray. length-2), последний элемент массива печатается. Когда значение 'i' становится равным (numberArray.length-1), значение для печати отсутствует. В этом месте возникает ArrayIndexOutOfBoundsException. Надеюсь, вы могли бы получить идея. спасибо!

GT_hash
источник
0

Вы можете использовать Optional в функциональном стиле, чтобы избежать NullPointerExceptionи ArrayIndexOutOfBoundsException:

String[] array = new String[]{"aaa", null, "ccc"};
for (int i = 0; i < 4; i++) {
    String result = Optional.ofNullable(array.length > i ? array[i] : null)
            .map(x -> x.toUpperCase()) //some operation here
            .orElse("NO_DATA");
    System.out.println(result);
}

Вывод:

AAA
NO_DATA
CCC
NO_DATA
Андрей Лаврухин
источник
-4

Вы не можете перебирать или хранить больше данных, чем длина вашего массива. В этом случае вы можете сделать так:

for (int i = 0; i <= name.length - 1; i++) {
    // ....
}

Или это:

for (int i = 0; i < name.length; i++) {
    // ...
}
Kevin7
источник