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должным образом.

Этот 0ne программист
источник
В java 8 вы можете использовать forEachметод: stackoverflow.com/questions/16635398/…
Виталий Федоренко

Ответы:

229

Правильно ли я делаю это в части итерации по Arraylist?

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

Самый простой способ написать этот цикл - использовать конструкцию for-each :

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

Что касается

java.lang.ArrayIndexOutOfBoundsException: -1

Вы просто пытались получить номер элемента -1из массива. Подсчет начинается с нуля.

Фред Фу
источник
1
Используйте for-each, это намного проще. Также возможно, что вы снова вызвали arrayList.iterator (). Next () и пропустили записи.
@ larsmans Большое спасибо. Я совершенно забыл, что вы можете сделать это с помощью списка массивов. Однако я попробовал это с помощью своего кода, и все равно получаю ту же ошибку. Итак, я думаю, что проблема в том, как я добавляю в arrayList ранее в коде, поэтому сейчас я рассмотрю это решение. Тем не менее, большое спасибо, что напомнили мне об этом.
This 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
}
НемезидаX00
источник
12
Мне кажется, это более точно отвечает на вопрос, поскольку это пример итератора, а не альтернативное решение.
withoutclass
1
Спасибо за проницательный ответ. for (...) итерация обычно является лучшим решением, но не всегда. Сегодня мне пришлось искать явно управляемый синтаксис итератора, и вот он.
Роберт Альтман
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
}
subbu
источник
8

Вы также можете выполнить цикл for, как и для массива, но вместо array [i] вы должны использовать list.get (i)

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}
Стас Яро
источник
7

Помимо ответа larsmans (который действительно прав), исключение в вызове метода get (), поэтому опубликованный вами код не является тем, который вызывает ошибку.

SJuan76
источник
4

Эффективный способ итерации ваш ArrayListпоследующее этой ссылкой . Этот тип улучшит производительность цикла во время итерации.

int size = list.size();

for(int j = 0; j < size; j++) {
    System.out.println(list.get(i));
}
Красный Череп
источник
2

итерация с использованием итератора не является отказоустойчивой, например, если вы добавляете элемент в коллекцию после создания итератора, тогда он вызовет исключение concurrentmodificaionexception. Кроме того, он не является потокобезопасным, вы должны сделать его потокобезопасным извне.

Так что лучше использовать структуру for-each цикла for. Это по крайней мере безотказно.

Сумит Кумар Саха
источник