ArrayIndexOutOfBoundsException при використанні ітератора ArrayList


103

Зараз у мене є програма, що містить фрагмент коду, який виглядає приблизно так:

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

Чи правильно я це роблю, наскільки йде повторення через ArrayList?

Я отримую помилку:

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)

Я б показав решту коду, але він досить обширний, і якщо я не роблю ітерацію правильно, я вважаю, що єдиною можливістю є те, що я не ініціалізую ArrayListналежним чином.


У java 8 ви можете використовувати forEach методом: stackoverflow.com/questions/16635398/…
Віталій Федоренко

Відповіді:


229

Чи правильно я це роблю, наскільки йде повторення через Arraylist?

Ні: закликаючи iteratorдвічі за кожну ітерацію, ви постійно отримуєте нові ітератори.

Найпростіший спосіб написання цього циклу - це використання конструкції для кожного :

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

Що стосується

java.lang.ArrayIndexOutOfBoundsException: -1

Ви просто намагалися отримати номер елемента -1з масиву. Підрахунок починається з нуля.


1
Використовувати для кожного, це набагато простіше. Також можливо, ви знову зателефонували arrayList.iterator (). Next () і пропустили записи.

@ larsmans Ах, дуже дякую Я зовсім забув, що ви могли це зробити за допомогою списку масивів. Однак я спробував це зі своїм кодом, і я все одно отримую ту саму помилку. Тому я думаю, що проблема в тому, як я додаю до масиву arrayList раніше код, тому я зараз розгляну його адресу. Все-таки дуже дякую, що нагадали про це.
Це 0ne Pr0grammer

люблю це для кожного оператора. Я використовую щось подібне в рубіні весь час ... do array.each |s| unless (s.nil?) end end
Девід Вест,

2
Зазначимо, Have you heard ofздається образливим (без причини), але я не рідний. Інакше чудово.
n611x007

3
@naxa: це може прийти як поблажливе, я змінив формулювання.
Фред Фоо

142

Хоча я згоден, що прийнята відповідь зазвичай є найкращим рішенням і, безумовно, простішим у використанні, я помітив, що ніхто не відображав належного використання ітератора. Ось ось короткий приклад:

Iterator<Object> it = arrayList.iterator();
while(it.hasNext())
{
    Object obj = it.next();
    //Do something with obj
}

12
Я відчуваю, що це більш точно відповідає на питання, оскільки це приклад ітератора замість альтернативного рішення.
безклас

1
Дякую за проникливу відповідь. для (...) ітерації зазвичай найкраще рішення, але не завжди. Сьогодні мені трапляється шукати явно керований синтаксис ітератора, і ось він.
Роберт Альтман

37
List<String> arrayList = new ArrayList<String>();
for (String s : arrayList) {
    if(s.equals(value)){
        //do something
    }
}

або

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

Але будьте обережні, ArrayList може містити нульові значення . Тож порівняння має бути

value.equals(arrayList.get(i))

коли ви впевнені, що значення не є нульовим, або ви повинні перевірити, чи вказаний елемент є нульовим.


10

Ви також можете використовувати так:

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

Хороша практика для відкидання та використання об'єкта. Наприклад, якщо 'arrayList' містить список об'єктів 'Object1'. Потім ми можемо переписати код у вигляді:

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

8

Ви також можете зробити цикл for, як і для масиву, але замість масиву [i] ви б використали list.get (i)

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

7

Окрім larsmans відповідають (хто насправді правильний), виняток у виклику методу get (), тому код, який ви опублікували, не той, що викликає помилку.


4

Ефективний спосіб повторити ваш ArrayListнаступний посилання . Цей тип покращить продуктивність циклу під час ітерації

int size = list.size();

for(int j = 0; j < size; j++) {
    System.out.println(list.get(i));
}

2

ітерація за допомогою ітератора не є безпечною, наприклад, якщо ви додаєте елемент у колекцію після створення ітератора, то вона викине паралельну modificaionexception. Крім того, це не є безпечним для потоків, ви повинні зробити його потоком безпечним зовні.

Тому краще використовувати для кожної структури для циклу. Це як мінімум безвідмовно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.