Ответ 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
.
Например, если у вас есть raw
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
Это также относится к 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
, если вам нужно знать индекс и значение:Это подвержено ошибкам, которые являются первичными причинами of
java.lang.ArrayIndexOutOfBoundsException
:
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 (final int i : ints)
{
System.out.format("%d", i);
System.out.println();
}
Использование безопасного итератора типа:
Вот безопасный способ итерации над необработанным
Array
с расширенным для цикла и отслеживания текущего индекса и избегает возможности столкнувшись с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());
}
Этот метод работает для всех Iterables
, это не Index
perse, но он дает вам текущую позицию на итерации даже для вещей, у которых нет родного Index
.
Самый безопасный способ:
Лучший способ - всегда использовать ImmutableLists/Set/Карты от Guava as а также:
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());
}
Резюме:
- Использование raw
Array
с трудом работать и в большинстве случаев его следует избегать. Они восприимчивы к иногда тонким одному из ошибок, у которых есть новые программисты, даже в те дниBASIC
- Современные идиомы Java используют безопасный тип
Collections
и избегают использования исходных структурArray
, если это вообще возможно. -
Immutable
Типы предпочтительны почти во всех случаях. -
Guava
- незаменимый инструментарий для современной разработки Java.