ArrayIndexOutOfBoundsException podczas korzystania z iteratora tablicy ArrayList

103

W tej chwili mam program zawierający fragment kodu, który wygląda następująco:

while (arrayList.iterator().hasNext()) {
     //value is equal to a String value
     if( arrayList.iterator().next().equals(value)) {
          // do something 
     }
}

Czy robię to dobrze, jeśli chodzi o iterację przez ArrayList?

Pojawia się błąd:

java.lang.ArrayIndexOutOfBoundsException: -1
    at java.util.ArrayList.get(Unknown Source)
    at main1.endElement(main1.java:244)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(Unknown Source)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at javax.xml.parsers.SAXParser.parse(Unknown Source)
    at main1.traverse(main1.java:73)
    at main1.traverse(main1.java:102)
    at main1.traverse(main1.java:102)
    at main1.main(main1.java:404)

Pokazałbym resztę kodu, ale jest dość obszerny i jeśli nie wykonam poprawnie iteracji, założyłbym, że jedyną możliwością jest to, że nie inicjalizuję ArrayListpoprawnie.

Ten program 0ne Pr0grammer
źródło
W java 8 możesz użyć forEachmetody: stackoverflow.com/questions/16635398/…
Vitalii Fedorenko

Odpowiedzi:

229

Czy robię to dobrze, jeśli chodzi o iterację przez Arraylist?

Nie: wołając iteratordwa razy w każdej iteracji, cały czas otrzymujesz nowe iteratory.

Najłatwiejszym sposobem napisania tej pętli jest użycie konstrukcji for-each :

for (String s : arrayList)
    if (s.equals(value))
        // ...

Jeśli chodzi o

java.lang.ArrayIndexOutOfBoundsException: -1

Właśnie próbowałeś pobrać numer elementu -1z tablicy. Liczenie zaczyna się od zera.

Fred Foo
źródło
1
Użyj dla każdego, jest to znacznie łatwiejsze. Możliwe jest również, że ponownie wywołałeś arrayList.iterator (). Next () i pominąłeś wpisy.
@ larsmans Ach, dziękuję bardzo. Całkowicie zapomniałem, że możesz to zrobić za pomocą tablicy tablic. Jednak próbowałem tego z moim kodem i nadal otrzymuję ten sam błąd. Więc myślę, że jest to problem ze sposobem dodawania do tablicy arrayList wcześniej w kodzie, więc teraz przyjrzę się adresowi. Mimo to bardzo dziękuję za przypomnienie mi o tym.
To 0ne Pr0grammer
uwielbiam to dla każdego operatora. Cały czas używam czegoś takiego w rubinie ... do array.each |s| unless (s.nil?) end end
David West,
2
Uwaga, Have you heard ofwydaje się trochę obraźliwa (bez powodu), ale nie jestem tubylcem. Poza tym świetnie.
n611x007
3
@naxa: może się to wydawać protekcjonalne, zmieniłem sformułowanie.
Fred Foo
142

Chociaż zgadzam się, że zaakceptowana odpowiedź jest zwykle najlepszym rozwiązaniem i zdecydowanie łatwiejsza w użyciu, zauważyłem, że nikt nie pokazał prawidłowego użycia iteratora. Oto krótki przykład:

Iterator<Object> it = arrayList.iterator();
while(it.hasNext())
{
    Object obj = it.next();
    //Do something with obj
}
NemesisX00
źródło
12
Wydaje mi się, że to dokładniej odpowiada na pytanie, ponieważ jest to przykład iteratora zamiast alternatywnego rozwiązania.
zajęć
1
Dziękuję za wnikliwą odpowiedź. dla (...) iteracja jest zwykle najlepszym rozwiązaniem, ale nie zawsze. Dzisiaj tak się składa, że ​​szukam jawnie zarządzanej składni iteratora i oto jest.
Robert Altman
37
List<String> arrayList = new ArrayList<String>();
for (String s : arrayList) {
    if(s.equals(value)){
        //do something
    }
}

lub

for (int i = 0; i < arrayList.size(); i++) {
    if(arrayList.get(i).equals(value)){
        //do something
    }
}

Ale zachowaj ostrożność ArrayList może przechowywać wartości null . Więc porównanie powinno być

value.equals(arrayList.get(i))

gdy jesteś pewien, że wartość nie jest null lub powinieneś sprawdzić, czy dany element jest pusty.

zacheusz
źródło
10

Możesz również użyć w ten sposób:

for(Iterator iterator = arrayList.iterator(); iterator.hasNext();) {
x = iterator.next();
//do some stuff
}

Dobrą praktyką jest rzucanie i używanie obiektu. Na przykład, jeśli „arrayList” zawiera listę obiektów „Object1”. Następnie możemy przepisać kod jako:

for(Iterator iterator = arrayList.iterator(); iterator.hasNext();) {
x = (Object1) iterator.next();
//do some stuff
}
subbu
źródło
8

Możesz również wykonać pętlę for, tak jak w przypadku tablicy, ale zamiast tablicy [i] użyjesz list.get (i)

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
Stas Jaro
źródło
7

Oprócz odpowiedzi larsmana (która rzeczywiście jest poprawna), wyjątek w wywołaniu metody get (), więc wysłany przez Ciebie kod nie jest tym, który powoduje błąd.

SJuan76
źródło
4

Wydajny sposób na iterację ArrayListśledzonego przez ten link . Ten typ poprawi wydajność zapętlania podczas iteracji

int size = list.size();

for(int j = 0; j < size; j++) {
    System.out.println(list.get(i));
}
Czerwona Czaszka
źródło
2

iteracja przy użyciu iteratora nie jest bezpieczna w przypadku awarii, na przykład jeśli dodasz element do kolekcji po utworzeniu iteratora, spowoduje to zgłoszenie wyjątku współbieżnego modyfikowania. Nie jest też bezpieczny wątkowo, musisz zadbać o to, aby był bezpieczny na zewnątrz.

Dlatego lepiej jest użyć pętli for-each. Jest przynajmniej bezawaryjny.

Sumit Kumar Saha
źródło