Что вызывает исключение java.lang.ArrayIndexOutOfBoundsException и как его предотвратить?
Что значит ArrayIndexOutOfBoundsException
значит и как мне от этого избавиться?
Вот пример кода, который вызывает исключение:
String[] name = {"tom", "dick", "harry"};
for (int i = 0; i <= name.length; i++) {
System.out.print(name[i] + '\n');
}
28 ответов
Ваш первый порт захода должен быть документацией, которая объясняет это достаточно ясно:
Брошенный, чтобы указать, что к массиву обращались с недопустимым индексом. Индекс либо отрицательный, либо больше или равен размеру массива.
Так, например:
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, сделайте это.)
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++) {
Короче говоря:
В последней итерации
for(int i = 0; i<=name.length; i++) {
i
будет равно name.length
это недопустимый индекс, так как индексы массива начинаются с нуля.
Ваш код должен читать
for(int i = 0; i < name.length; i++)
^
Это означает, что вы пытаетесь получить доступ к индексу массива, который недопустим, поскольку не находится между границами.
Например, это инициализирует массив целых примитивов с верхней границей 4.
int intArray[] = new int[5];
Программисты считают с нуля. Так это например бросило бы ArrayIndexOutOfBoundsException
в качестве верхней границы 4, а не 5.
intArray[5];
Что вызывает ArrayIndexOutOfBoundsException
?
Если вы думаете о переменной как о "ящике", в котором вы можете поместить значение, тогда массив - это серия ячеек, расположенных рядом друг с другом, где число ящиков является конечным и явным целым числом.
Создание массива, как это:
final int[] myArray = new int[5]
создает ряд из 5 коробок, каждая из которых содержит int
, У каждого из ящиков есть индекс, позиция в ряду ящиков. Этот индекс начинается с 0 и заканчивается в N-1, где N - размер массива (количество блоков).
Чтобы извлечь одно из значений из этой серии блоков, вы можете обратиться к нему через его индекс, например:
myArray[3]
Что даст вам значение 4-го блока в серии (так как первый блок имеет индекс 0).
ArrayIndexOutOfBoundsException
вызвано попыткой извлечь "ящик", который не существует, путем передачи индекса, который выше индекса последнего "ящика", или отрицательным.
В моем работающем примере эти фрагменты кода выдают такое исключение:
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];
}
Чтобы избежать исключения за пределами индекса массива, следует использовать расширенный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");
}
В вашем коде вы получили доступ к элементам от индекса 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');
}
Для вашего данного массива длина массива равна 3(т.е. name.length = 3). Но поскольку он хранит элемент, начиная с индекса 0, он имеет максимальный индекс 2.
Таким образом, вместо "i **<= name.length" вы должны написать "i<** name.length", чтобы избежать "ArrayIndexOutOfBoundsException".
Так много для этого простого вопроса, но я просто хотел выделить новую функцию в 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
Для многомерных массивов может быть сложно убедиться, что вы получаете доступ к 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
, для простоты).
Наиболее распространенный случай, который я видел для, казалось бы, загадочных 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, одновременно, как в сервлете или контроллере. Проверьте все переменные экземпляра ваших сервлетов и контроллеров на наличие возможных подозреваемых.
Вы получаете 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
может быть положительным или нулевым.
Вот как выглядит этот тип исключения, когда выдается в 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
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
}
ArrayIndexOutOfBoundsException всякий раз, когда возникает это исключение, это означает, что вы пытаетесь использовать индекс массива, выходящий за его пределы, или, в терминах непрофессионала, вы запрашиваете больше, чем инициализировали.
Чтобы предотвратить это, всегда проверяйте, что вы не запрашиваете индекс, которого нет в массиве, т.е. если длина массива равна 10, тогда ваш индекс должен находиться в диапазоне от 0 до 9
Для любого массива длины n элементы массива будут иметь индекс от 0 до n-1.
Если ваша программа пытается получить доступ к любому элементу (или памяти) с индексом массива, превышающим n-1, Java выдаст исключение ArrayIndexOutOfBoundsException
Итак, вот два решения, которые мы можем использовать в программе
Ведение счета:
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++; }
Лучший способ - использовать цикл для каждого цикла, в этом методе программисту не нужно беспокоиться о количестве элементов в массиве.
for(String str : array) { System.out.println(str); }
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
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);
Каждый элемент в массиве называется элементом, и каждый элемент доступен по его числовому индексу. Как показано на предыдущем рисунке, нумерация начинается с 0. Таким образом, к 9-му элементу, например, будет осуществляться доступ по индексу 8.
Выдается исключение IndexOutOfBoundsException, указывающее, что какой-то индекс (например, массив, строка или вектор) находится за пределами диапазона.
Доступ к любому массиву X возможен от [0 до (X.length - 1)]
Я вижу все ответы здесь, объясняющие, как работать с массивами и как избегать исключений индекса за пределами границ. Я лично избегаю массивов любой ценой. Я использую классы Collections, что исключает всю глупость необходимости полностью разбираться с индексами массивов. Циклические конструкции прекрасно работают с коллекциями, поддерживающими код, который легче писать, понимать и поддерживать.
Если вы используете длину массива для управления итерацией цикла for, всегда помните, что индекс первого элемента в массиве равен 0. Таким образом, индекс последнего элемента в массиве на единицу меньше длины массива.
Согласно вашему Кодексу:
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');
}
ArrayIndexOutOfBoundsException
само имя объясняет, что если вы пытаетесь получить доступ к значению в индексе, которое выходит за рамки размера массива, то возникает такой тип исключения.
В вашем случае вы можете просто удалить знак равенства из цикла for.
for(int i = 0; i<name.length; i++)
Лучшим вариантом является итерация массива:
for(String i : name )
System.out.println(i);
Здесь 0-> tom, 1->bob,2 ->harry . Но индекса для 3 нет. Здесь значение
names.length
является
3
. Итак, в цикле for вы получаете доступ к индексу 3. Итак, ошибка приближается. просто измени
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length -1 ; i++) {
System.out.println(names[i]);
}
избежать
ArrayIndexOutOfBoundsException
Исключение ArrayIdexOutOfBoundException возникает при попытке доступа к индексу несуществующего массива. В вашем сценарии, когда я = 3, вы пытаетесь получить третий индекс массива имен. Но массив имен содержит значения до второго индекса.
Поскольку в третьем индексе массива нет значения, выдается это исключение.
Эта ошибка возникает при превышении лимита цикла выполнения. Давайте рассмотрим простой пример, подобный этому,
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. Я надеюсь, что вы могли бы получить идея. спасибо!
В большинстве языков программирования индексы начинаются с 0, поэтому вам необходимо написать i <names.length или i<=names.length-1 вместо i<=names.length.
Вы можете использовать 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
Вы не можете перебирать или хранить больше данных, чем длина вашего массива. В этом случае вы можете сделать так:
for (int i = 0; i <= name.length - 1; i++) {
// ....
}
Или это:
for (int i = 0; i < name.length; i++) {
// ...
}