¿Cómo puedo evitar ArrayIndexOutOfBoundsException o IndexOutOfBoundsException? [duplicar]

Resuelto asked hace 9 años • 2 respuestas

Si su pregunta es: Recibo un error java.lang.ArrayIndexOutOfBoundsExceptionen mi código y no entiendo por qué sucede, ¿qué significa y cómo puedo evitarlo?

Esta pretende ser la colección canónica más completa de información sobre este java.lang.ArrayIndexOutOfBoundsExceptiontema, así como sobre java.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 están localizadas en 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 se incluye en este caso general, en lugar de responderlo con más contenido especializado duplicado, márquelo como un duplicado de este.

 avatar Sep 14 '15 22:09
Aceptado

¿Qué es java.lang.ArrayIndexOutOfBoundsException/java.lang.IndexOutOfBoundsException?

El JavaDoc dice brevemente:

Se lanza 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é causa que esto suceda?

Esta excepción significa que ha intentado acceder a un índice en una matriz o en una lista respaldada por matrices y ese índice no existe.

Java utiliza 0índices basados. Eso significa que todos los índices comienzan con 0el índice del primer elemento si contiene algún elemento.

El IndexOutOfBoundsExceptionmensaje es muy explícito y suele adoptar la forma de:

java.lang.IndexOutOfBoundsException: Index: 1, Size: 1

¿Dónde Indexestá el índice que solicitó y que no existe y Sizees la longitud de la estructura en la que estaba indexando?

Como puede ver, Size: 1significa que el único índice válido es 0y usted estaba preguntando qué había en el índice 1.

Por ejemplo, si tiene un conjunto Arrayde objetos o tipos primitivos, los índices válidos son 0, .length - 1en el siguiente ejemplo los índices válidos serían 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

Esto también se aplica a ArrayListcualquier otra Collectionclase que pueda estar respaldada por un índice Arrayy permita el acceso directo al mismo.

¿Cómo evitar el java.lang.ArrayIndexOutOfBoundsException/ java.lang.IndexOutOfBoundsException?

Al acceder directamente por índice:

Esto utiliza Guava para convertir la int[]matriz primitiva sin formato en un archivo ImmutableList<Integer>. Luego usa la Iterablesclase para obtener de forma segura el valor en un índice particular y proporciona un valor predeterminado cuando ese índice no existe. Aquí elegí -1indicar 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 no puede usar Guava por alguna razón, es fácil implementar 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:

Estas son las formas idiomáticas de iterar sobre un archivo sin formato Arraysi necesita conocer el índice y el valor:

Esto es susceptible a errores puntuales que son las causas principales de java.lang.ArrayIndexOutOfBoundsException:

Usando un bucle tradicional 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]);
}

Usando un bucle mejorado para cada uno :

Esta es la forma idiomática de iterar sobre un archivo raw Arraycon 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 Iterador <T> de tipo seguro:

Esta es la forma segura de iterar sobre un archivo sin formato Arraycon el bucle for mejorado y realizar un seguimiento del índice actual y evitar la posibilidad de encontrar un archivo java.lang.ArrayIndexOutOfBoundsException.

Esto utiliza Guava para convertir fácilmente el archivo int[]en algo Iterable que cada 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 puedes usar guayaba o la tuya int[]es enorme, puedes enrollar la tuya ImmutableIntArrayIteratorcomo 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 usa el mismo código que usarías con Guava.

Si es absolutamente necesario tener el ordinal del elemento, 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 análisis de índice , pero le brinda la posición actual en la iteración incluso para cosas que no tienen un índice nativo .

La forma más segura:

La mejor manera es usar siempre ImmutableLists / Set / Maps de 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:

  1. Es difícil trabajar con matrices sin formato y debe evitarse en la mayoría de los casos. Son susceptibles a errores únicos, a veces sutiles , que han afectado a los nuevos programadores incluso desde los días de BASIC .

  2. Los modismos modernos de Java utilizan colecciones seguras de tipo adecuado y, si es posible, evitan el uso de estructuras de matriz sin formato.

  3. Actualmente se prefieren los tipos inmutables en casi todos los casos.

  4. Guava es un conjunto de herramientas indispensable para el desarrollo moderno de Java.

 avatar Sep 14 '2015 15:09