java - que - ¿Cómo evitar ArrayIndexOutOfBoundsException o IndexOutOfBoundsException?
array index out of bounds exception java (2)
¿Qué es java.lang.ArrayIndexOutOfBoundsException / java.lang.IndexOutOfBoundsException?
El JavaDoc dice brevemente:
Lanzado para indicar que se ha accedido a una matriz con un índice ilegal. El índice es negativo o mayor o igual que el tamaño de la matriz.
¿Qué hace que suceda?
Esta excepción significa que ha intentado acceder a un índice en una matriz o lista respaldada por matriz y ese índice no existe.
Java usa
0
índices basados. Eso significa que todos los índices comienzan con0
como el índice del primer elemento si contiene algún elemento.
El mensaje
IndexOutOfBoundsException
es muy explícito, generalmente toma la forma de:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
Donde
Index
es el índice que solicitó que no existe y
Size
es la longitud de la estructura en la que estaba indexando.
Como puede ver, un
Size: 1
significa que el único índice válido es
0
y estaba preguntando qué estaba en el índice
1
.
Por ejemplo, si tiene una
Array
sinArray
de objetos o tipos primitivos, los índices válidos son0
a.length - 1
, en el siguiente ejemplo los índices válidos serían0,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
Esto también se aplica a
ArrayList
, así como a cualquier otra clase de
Collection
que pueda estar respaldada por un
Array
y permitir el acceso directo al índice.
¿Cómo evitar la
java.lang.ArrayIndexOutOfBoundsException
/
java.lang.IndexOutOfBoundsException
?
Al acceder directamente por índice:
Esto usa Guava para convertir la matriz primitiva sin procesar
int[]
en unaImmutableList<Integer>
. Luego usa la claseIterables
para obtener de forma segura el valor en un índice particular y proporciona un valor predeterminado cuando ese índice no existe. Aquí elegí-1
para indicar un valor de índice no válido.
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));
Si por alguna razón no puede usar
Guava
, es fácil usar su propia función para hacer lo mismo.
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;
}
}
Al iterar:
Usando un bucle for / next tradicional:Estas son las formas idiomáticas de iterar sobre una
Array
sinArray
si necesita conocer el índice y el valor:Esto es susceptible a errores únicos que son las causas principales de una
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]);
}
Usando un mejorado para / cada ciclo:
Aquí está la forma idiomática de iterar sobre una
Array
sinArray
con el bucle for mejorado si no necesita conocer el índice real:
for (final int i : ints)
{
System.out.format("%d", i);
System.out.println();
}
Usando un tipo seguro Iterator:
Aquí está la forma segura de iterar sobre una
Array
sinArray
con el bucle for mejorado y rastrear el índice actual y evita la posibilidad de encontrar unajava.lang.ArrayIndexOutOfBoundsException
.Esto usa Guava para convertir fácilmente el
int[]
en algoIterable
todo proyecto debería incluir.
final Iterator<Integer> it = Ints.asList(ints).iterator();
for (int i = 0; it.hasNext(); i++)
{
System.out.format("index %d = %d", i, it.next());
}
Si no puede usar Guava o su
int[]
es enorme, puede rodar su propio
ImmutableIntArrayIterator
como tal:
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(); }
}
Y use el mismo código que usaría con Guava.
Si debe tener el ordinal del artículo, la siguiente es la forma más segura de hacerlo.
// 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());
}
Esta técnica funciona para todos los
Iterables
, no es un
index
persecución, pero le da la posición actual en la iteración incluso para cosas que no tienen un
index
nativo.
La forma mas segura:
La mejor manera es usar siempre ImmutableList<Integer> / Set / Maps from Guava también:
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());
}
Resumen:
-
El uso de
Array
procesar es difícil de trabajar y se debe evitar en la mayoría de los casos. Son susceptibles a errores ocasionales sutiles que han afectado a los nuevos programadores incluso desde los días deBASIC
-
Las expresiones idiomáticas modernas de Java utilizan
Collections
seguras de tipo adecuado y evitan el uso de estructuras deArray
sinArray
si es posible. -
Immutable
tiposImmutable
se prefieren en casi todos los casos ahora. -
Guava
es un kit de herramientas indispensable para el desarrollo moderno de Java.
Esta pregunta ya tiene una respuesta aquí:
Si su pregunta es
, estoy obteniendo una
java.lang.ArrayIndexOutOfBoundsException
en mi código y no entiendo por qué está sucediendo.
¿Qué significa y cómo puedo evitarlo?
Se supone que es la recopilación de información Canonical más completa sobre este tema
java.lang.ArrayIndexOutOfBoundsException
, así como eljava.lang.IndexOutOfBoundsException
.
Hay muchas preguntas como esta y todas tienen respuestas vagas sin código, o en su mayoría son extremadamente específicas y localizadas para la pregunta en cuestión y no abordan la causa raíz, que es exactamente la misma en todos los casos.
Si ve uno que cae dentro de este caso general, en lugar de responderlo con más contenido especializado duplicado, márquelo como un duplicado de este.
En referencia a la documentación de Java Class ArrayIndexOutOfBoundsException , esta excepción se produce cuando intenta acceder a un elemento que es negativo o mayor que el tamaño de la matriz.
Considere el caso de que tenga 10 elementos en la matriz. Puede preguntarle al sistema cuál es el primero al décimo elemento dentro de la matriz. Si intenta preguntar cuál es el elemento -1 o el elemento número 100 de la matriz, Java responderá con la excepción anterior. Ahora tenga en cuenta que Array en Java está indexado 0. Por lo tanto, solo puede pasar un valor de índice de 0 a 9 inclusive. Cualquier número que no esté en este rango arrojará el error específico mencionado anteriormente.
Para evitar esta excepción, volvamos al concepto de CS101 y revisemos el concepto de bucle invariante. Esta es una condición para asegurarse de que la variable que utiliza para almacenar el índice debe cumplir con la condición particular.
Aquí hay un enlace a loop invariant: wikipedia> Loop invariant