Co powoduje wyjątek java.lang.ArrayIndexOutOfBoundsException i jak temu zapobiec?

298

Co robi ArrayIndexOutOfBoundsException znaczy i jak się go pozbyć?

Oto przykładowy kod, który wyzwala wyjątek:

String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
    System.out.println(names[i]);
}
Aaron
źródło
1
W odniesieniu do ostatniego pytania pomocny byłby kod. Czy uzyskujesz dostęp do tablicy ze znanym indeksem, czy musisz rozpocząć debugowanie, aby dowiedzieć się, w jaki sposób obliczany jest indeks po wystąpieniu błędu?
justkt
43
Wymienić i <= name.lengthz i < name.length- lub lepiej napisać zwiększona do pętli. ( for (String aName : name) { ... })
Jean Hominal,
1
oznacza to, że chcesz uzyskać element tablicy, który nie istnieje, „i <= name.length” oznacza, że ​​chcesz uzyskać długość elementu + 1 - nie istnieje.
gbk

Odpowiedzi:

296

Pierwszym portem zawinięcia powinna być dokumentacja, która wyjaśnia to dość wyraźnie:

Wyrzucony, aby wskazać, że dostęp do tablicy został uzyskany z niedozwolonym indeksem. Indeks jest albo ujemny, albo większy lub równy rozmiarowi tablicy.

Na przykład:

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

Co do tego, jak tego uniknąć ... nie rób tego. Uważaj na indeksy tablic.

Jednym z problemów, na który natrafiają ludzie, jest myślenie, że tablice mają indeks 1, np

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

Spowoduje to pominięcie pierwszego elementu (indeks 0) i wyrzuci wyjątek, gdy indeks wynosi 5. Prawidłowe tutaj indeksy to 0-4 włącznie. Prawidłowe, idiomatyczne forstwierdzenie brzmi :

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

(Zakładając, że potrzebujesz indeksu, oczywiście. Jeśli zamiast tego możesz użyć rozszerzonej pętli for, zrób to.)

Jon Skeet
źródło
1
Chciałbym dodać, że dla wielowymiarowych tablic, które mogą mieć dowolny kształt w Javie, zagnieżdżone pętle powinien sprawdzać odpowiedniej długości subarray: for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }.
Andrey
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];
}

Zobacz też:


Aktualizacja : zgodnie z fragmentem kodu,

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

Indeks zawiera długość tablicy. To jest poza zasięgiem. Trzeba zastąpić <=przez <.

for (int i = 0; i < name.length; i++) {
BalusC
źródło
22

Z tego doskonałego artykułu: ArrayIndexOutOfBoundsException in for loop

Krótko mówiąc:

W ostatniej iteracji

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

i będzie równy name.length co jest niedozwolonym indeksem, ponieważ indeksy tablicowe są zerowe.

Twój kod powinien przeczytać

for (int i = 0; i < name.length; i++) 
                  ^
aioobe
źródło
17

Oznacza to, że próbujesz uzyskać dostęp do indeksu tablicy, który jest niepoprawny, ponieważ nie znajduje się między granicami.

Na przykład zainicjowałoby to pierwotną tablicę liczb całkowitych z górną granicą 4.

int intArray[] = new int[5];

Programiści liczą od zera. Na przykład wyrzuciłoby to, ArrayIndexOutOfBoundsExceptionponieważ górna granica wynosi 4, a nie 5.

intArray[5];
Oktawian A. Damiean
źródło
4
Granice są granicami w zasięgu. to znaczy; 0-5
John Giotta,
11

Aby uniknąć wyjątku poza zakresem indeksu tablicy, należy użyć instrukcji rozszerzonejfor gdzie i kiedy mogą.

Podstawowa motywacja (i przypadek użycia) ma miejsce podczas iteracji i nie wymaga żadnych skomplikowanych kroków iteracji. Byś nie być w stanie korzystać z enhanced-for aby przesunąć wstecz w tablicy lub tylko iterate na każdym innym elemencie.

Gwarantujesz, że nie zabraknie Ci elementów do iteracji, a Twój [poprawiony] przykład można łatwo przekonwertować.

Kod poniżej:

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

... odpowiada temu:

String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
    System.out.println(firstName + "\n");
}
Makoto
źródło
11

Co jest przyczyną ArrayIndexOutOfBoundsException?

Jeśli myślisz o zmiennej jako „polu”, w którym możesz umieścić wartość, to tablica to seria pól umieszczonych obok siebie, gdzie liczba pól jest skończoną i jawną liczbą całkowitą.

Tworzenie takiej tablicy:

final int[] myArray = new int[5]

tworzy rząd 5 pól, każde z nich zawiera int. Każde z pól ma indeks, pozycję w szeregu pól. Indeks zaczyna się od 0, a kończy na N-1, gdzie N jest rozmiarem tablicy (liczba pól).

Aby pobrać jedną z wartości z tej serii pól, możesz odwołać się do niej poprzez jej indeks, jak poniżej:

myArray[3]

Który da ci wartość czwartego pola w serii (ponieważ pierwsze pole ma indeks 0).

Na ArrayIndexOutOfBoundsException to spowodowane próbą odzyskania „nieistniejącego” pola, przekazaniem indeksu wyższego niż indeks ostatniego „pola” lub ujemnego.

W moim działającym przykładzie te fragmenty kodu spowodowałyby taki wyjątek:

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

Jak ominąć ArrayIndexOutOfBoundsException

Aby temu zapobiec ArrayIndexOutOfBoundsException, należy wziąć pod uwagę kilka kluczowych punktów:

Pętla

Przechodząc przez tablicę, zawsze upewnij się, że indeks, który pobierasz, jest ściśle mniejszy niż długość tablicy (liczba pól). Na przykład:

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

Zauważ, że <nigdy =tam nie mieszaj …

Możesz mieć ochotę zrobić coś takiego:

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

Po prostu nie. Trzymaj się powyższego (jeśli musisz użyć indeksu), a zaoszczędzi ci to dużo bólu.

Gdzie to możliwe, użyj foreach:

for (int value : myArray) {

W ten sposób nie będziesz musiał w ogóle myśleć o indeksach.

Podczas wykonywania pętli, cokolwiek robisz, NIGDY nie zmieniaj wartości iteratora pętli (tutaj: i . Jedynym miejscem, w którym powinna to zmienić wartość, jest utrzymanie pętli. Zmiana go w inny sposób ryzykuje wyjątek i w większości przypadków nie jest konieczna.

Pobieranie / aktualizacja

Podczas pobierania dowolnego elementu tablicy zawsze sprawdzaj, czy jest to prawidłowy indeks względem długości tablicy:

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
źródło
6

W swoim kodzie uzyskałeś dostęp do elementów od indeksu 0 do długości tablicy łańcuchów. name.lengthpodaje liczbę obiektów łańcuchowych w tablicy obiektów łańcuchowych, tj. 3, ale można uzyskać dostęp tylko do indeksu 2 name[2], ponieważ do tablicy można uzyskać dostęp od indeksu 0 do name.length - 1miejsca, w którym otrzymujesz name.lengthliczbę obiektów.

Nawet podczas korzystania z forpętli zacząłeś od indeksu zero i powinieneś go zakończyć name.length - 1. W tablicy [n] możesz uzyskać dostęp od [0] do [n-1].

Na przykład:

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

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

W Twoim przypadku:

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

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'\n');
}
Chowdary Madhusudan
źródło
5

Dla podanej tablicy długość tablicy wynosi 3 (tj. Name.length = 3). Ale ponieważ przechowuje element zaczynający się od indeksu 0, ma maksymalny indeks 2.

Dlatego zamiast „i ** <= name.length” należy napisać „i <** name.length”, aby uniknąć „ArrayIndexOutOfBoundsException”.

NIKHIL
źródło
3

Tyle o tym prostym pytaniu, ale chciałem tylko podkreślić nową funkcję w Javie, która pozwoli uniknąć nieporozumień związanych z indeksowaniem tablic nawet dla początkujących. Java-8 wyodrębniła dla ciebie zadanie iteracji.

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]); })

Jaka jest korzyść? Cóż, jedna rzecz to czytelność jak angielski. Po drugie, nie musisz się martwić oArrayIndexOutOfBoundsException

Satyendra Kumar
źródło
3

Dostajesz z ArrayIndexOutOfBoundsExceptionpowodu i<=name.lengthczęści. name.lengthzwraca długość ciągu name, który wynosi 3. Stąd, gdy próbujesz uzyskać dostęp name[3], jest to nielegalne i zgłasza wyjątek.

Rozwiązany kod:

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

Jest zdefiniowany w specyfikacji języka Java :

public finalPole length, które zawiera liczbę elementów macierzy. lengthmoże być dodatnia lub zerowa.

roottraveller
źródło
3

Indeks tablicy poza wyjątkiem

Tak wygląda ten typ wyjątku, gdy zostanie zgłoszony w Eclipse. Liczba na czerwono oznacza indeks, do którego próbowano uzyskać dostęp. Więc kod wyglądałby tak:

myArray[5]

Błąd jest zgłaszany podczas próby uzyskania dostępu do indeksu, który nie istnieje w tej tablicy. Jeśli tablica ma długość 3,

int[] intArray = new int[3];

jedynymi poprawnymi indeksami są:

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

Jeśli tablica ma długość 1,

int[] intArray = new int[1];

wówczas jedynym poprawnym indeksem jest:

intArray[0]

Każda liczba całkowita równa długości tablicy lub większa niż to: jest poza zakresem.

Każda liczba całkowita mniejsza niż 0: jest poza zakresem;

PS: Jeśli chcesz lepiej zrozumieć tablice i wykonać kilka praktycznych ćwiczeń, tutaj jest wideo: samouczek na temat tablic w Javie

Johny
źródło
3

W przypadku tablic wielowymiarowych uzyskanie dostępu do lengthwłaściwości odpowiedniego wymiaru może być trudne . Weźmy na przykład następujący kod:

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();
}

Każdy wymiar ma inną długość, więc subtelny błąd polega na tym, że środkowa i wewnętrzna pętla używają lengthwłaściwości tego samego wymiaru (ponieważ a[i].lengthjest taki sam jak a[j].length).

Zamiast tego należy użyć pętli wewnętrznej a[i][j].length(lub a[0][0].length, dla uproszczenia).

Bill jaszczurka
źródło
Dodano przykład kodu z Dlaczego moja pętla for nie działa, gdy zmieniam warunek (tablice wielowymiarowe)? ponieważ to pytanie jest używane jako cel dupe dla każdego pytania dotyczącego wyjątku ArrayIndexOutOfBoundsException.
Bill the Lizard
2

Najczęstszym przypadkiem, jaki widziałem dla pozornie tajemniczych ArrayIndexOutOfBoundsExceptions, tj. Najwyraźniej nie spowodowanych własnym kodem obsługi tablicy, jest równoczesne użycie SimpleDateFormat. W szczególności w serwletie lub kontrolerze:

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

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

Jeśli dwa wątki wprowadzą razem metodę SimplateDateFormat.parse (), prawdopodobnie zobaczysz wyjątek ArrayIndexOutOfBoundsException. Zwróć uwagę na sekcję synchronizacji klasy javadoc dla SimpleDateFormat .

Upewnij się, że w kodzie nie ma miejsca, które ma dostęp do niebezpiecznych klas wątków, takich jak SimpleDateFormat, w sposób równoczesny, np. W serwletie lub kontrolerze. Sprawdź wszystkie zmienne instancji serwletów i kontrolerów pod kątem prawdopodobnych podejrzanych.

Kyri Sarantakos
źródło
2

ArrayIndexOutOfBoundsException za każdym razem, gdy nadchodzi ten wyjątek, oznacza to, że próbujesz użyć indeksu tablicy, który jest poza jego granicami lub, w kategoriach laików, żądasz więcej niż zainicjowałeś.

Aby temu zapobiec, zawsze upewnij się, że nie żądasz indeksu, który nie jest obecny w tablicy, tj. Jeśli długość tablicy wynosi 10, wówczas twój indeks musi zawierać się w przedziale od 0 do 9

sgrpwr
źródło
2

ArrayIndexOutOfBounds oznacza, że ​​próbujesz zaindeksować pozycję w tablicy, która nie jest przydzielona.

W tym przypadku:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length ma wartość 3, ponieważ tablica została zdefiniowana za pomocą 3 obiektów String.
  • Podczas uzyskiwania dostępu do zawartości tablicy pozycja zaczyna się od 0. Ponieważ są 3 elementy, oznaczałoby to imię [0] = "tom", imię [1] = "kutas" i imię [2] = "harry
  • Gdy pętla, ponieważ I może być mniejsza niż lub równa name.length, staramy się nazwy dostępu [3], który nie jest dostępny.

Aby obejść ten problem ...

  • W swojej pętli for możesz zrobić i <name.length. Zapobiegnie to zapętleniu nazwy [3], a zamiast tego zatrzyma się przy nazwie [2]

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

  • Użyj a dla każdej pętli

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

  • Użyj list.forEach (akcja konsumenta) (wymaga Java8)

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

  • Konwertuj tablicę na strumień - jest to dobra opcja, jeśli chcesz wykonywać dodatkowe „operacje” na tablicy, np. Filtrować, przekształcać tekst, konwertować na mapę itp. (Wymaga Java8)

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

martinywwan
źródło
1

ArrayIndexOutOfBoundsExceptionoznacza, że ​​próbujesz uzyskać dostęp do indeksu tablicy, który nie istnieje lub jest poza jej granicami. Indeksy tablic zaczynają się od 0 i kończą na długości - 1 .

W Twoim przypadku

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

ArrayIndexOutOfBoundsExceptionzdarza się, gdy próbujesz uzyskać dostęp do elementu indeksowanego name.length, który nie istnieje (indeks tablicy kończy się na długości -1). samo zastąpienie <= na <rozwiązałoby ten problem.

for(int i = 0; i < name.length; i++) {
    System.out.print(name[i] +'\n');  // i goes from 0 to length - 1, Correct
}
i 911
źródło
1

Dla dowolnej tablicy o długości n elementy tablicy będą miały indeks od 0 do n-1.

Jeśli twój program próbuje uzyskać dostęp do dowolnego elementu (lub pamięci) o indeksie tablic większym niż n-1, wówczas Java zgłosi wyjątek ArrayIndexOutOfBoundsException

Oto dwa rozwiązania, które możemy wykorzystać w programie

  1. Utrzymanie liczby:

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

    Lub jakieś inne zdanie zapętlające się jak

    int count = 0;
    while(count < array.length) {
        System.out.println(array[count]);
        count++;
    }
  2. Lepszym rozwiązaniem jest użycie dla każdej pętli, w tej metodzie programista nie musi zawracać sobie głowy liczbą elementów w tablicy.

    for(String str : array) {
        System.out.println(str);
    }
Mohit
źródło
1

Zgodnie z Twoim kodeksem:

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

Jeśli zaznaczysz System.out.print (name.length);

dostaniesz 3;

oznacza to, że twoje imię to 3

twoja pętla działa od 0 do 3, która powinna być „0 do 2” lub „1 do 3”

Odpowiedź

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
  System.out.print(name[i] +'\n');
}
Abhishek Agarwal
źródło
1

Każdy element w tablicy jest nazywany elementem, a do każdego elementu można uzyskać dostęp za pomocą indeksu liczbowego. Jak pokazano na poprzedniej ilustracji, numeracja zaczyna się od 0 . Na przykład, dziewiąty element byłby zatem dostępny pod indeksem 8.

IndexOutOfBoundsException jest zgłaszany, aby wskazać, że jakiś indeks (taki jak tablica, ciąg lub wektor) jest poza zakresem.

Dostęp do dowolnej tablicy X można uzyskać od [0 do (X.length - 1)]

ZiadM
źródło
1

Widzę tutaj wszystkie odpowiedzi wyjaśniające, jak pracować z tablicami i jak unikać indeksu poza wyjątkami. Osobiście unikam tablic za wszelką cenę. Korzystam z klas Kolekcje, co pozwala uniknąć wszelkich głupot związanych z całkowitym radzeniem sobie z indeksami tablic. Zapętlone konstrukcje wspaniale działają z kolekcjami obsługującymi kod, który jest zarówno łatwiejszy do pisania, zrozumienia, jak i utrzymania.

John Czukkermann
źródło
1

Jeśli używasz długości tablicy do kontrolowania iteracji pętli for , zawsze pamiętaj, że indeks pierwszego elementu w tablicy wynosi 0 . Zatem indeks ostatniego elementu w tablicy jest o jeden mniejszy niż długość tablicy.

Sachithra Dilshan
źródło
0

ArrayIndexOutOfBoundsException sama nazwa wyjaśnia, że ​​jeśli próbujesz uzyskać dostęp do wartości w indeksie, który jest poza zakresem rozmiaru tablicy, wystąpi tego rodzaju wyjątek.

W twoim przypadku możesz po prostu usunąć znak równości z pętli for.

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

Lepszą opcją jest iteracja tablicy:

for(String i : name )
      System.out.println(i);
Madhusudan Sharma
źródło
0

Ten błąd występuje w czasach przekroczenia limitu pętli uruchomień. Rozważmy prosty przykład taki jak ten:

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]+"  ");
    }
}

Na początku zainicjowałem tablicę jako „numberArray”. następnie niektóre elementy tablicy są drukowane przy użyciu pętli for. Gdy pętla działa w trybie „i”, wydrukuj element (liczbaArray [i + 1] .. (gdy wartość i wynosi 1, drukowany jest element numberArray [i + 1]). Załóżmy, że gdy i = (liczbaArray. length-2), wypisywany jest ostatni element tablicy. Gdy wartość „i” idzie do (numberArray.length-1), nie ma wartości do drukowania .. W tym momencie występuje „ArrayIndexOutOfBoundsException”. Mam nadzieję, że uda ci się uzyskać pomysł. dziękuję!

GT_hash
źródło
0

Możesz użyć Opcjonalnie w funkcjonalnym stylu, aby uniknąć NullPointerExceptioni 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);
}

Wynik:

AAA
NO_DATA
CCC
NO_DATA
Andrey Lavrukhin
źródło
-4

Nie można iterować ani przechowywać większej liczby danych niż długość tablicy. W takim przypadku możesz wykonać następujące czynności:

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

Albo to:

for (int i = 0; i < name.length; i++) {
    // ...
}
Kevin7
źródło