ArrayIndexOutOfBoundsException ao usar o iterador de ArrayList

103

No momento, tenho um programa que contém um trecho de código semelhante a este:

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

Estou fazendo isso certo, no que diz respeito à iteração por meio da ArrayList?

O erro que estou recebendo é:

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)

Eu mostraria o resto do código, mas é bastante extenso e, se não estou fazendo a iteração corretamente, presumo que a única possibilidade é não estar inicializando ArrayListcorretamente.

Este 0ne Pr0grammer
fonte
Em java 8, você pode usar o forEachmétodo: stackoverflow.com/questions/16635398/…
Vitalii Fedorenko

Respostas:

229

Estou fazendo isso certo, no que diz respeito à iteração pelo Arraylist?

Não: chamando iteratorduas vezes em cada iteração, você obtém novos iteradores o tempo todo.

A maneira mais fácil de escrever esse loop é usando a construção for-each :

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

Quanto a

java.lang.ArrayIndexOutOfBoundsException: -1

Você acabou de tentar obter o número -1do elemento de uma matriz. A contagem começa em zero.

Fred Foo
fonte
1
Use para cada um, é muito mais fácil. Também é possível que você tenha chamado arrayList.iterator (). Next () novamente e pulado as entradas.
@ larsmans Ah, muito obrigado. Eu esqueci totalmente que você poderia fazer isso com o array List. No entanto, tentei fazer isso com meu código e ainda estou recebendo o mesmo erro. Portanto, acho que é um problema de como estou adicionando ao arrayList no início do código, então agora examinarei como resolver isso. Ainda assim, muito obrigado por me lembrar disso.
Este 0ne Pr0grammer
amo isso para cada operador. Eu uso algo assim em ruby ​​o tempo todo ... do array.each |s| unless (s.nil?) end end
David West,
2
Só para notar, Have you heard ofparece meio ofensivo (sem motivo), mas não sou nativo. Caso contrário, ótimo.
n611x007
3
@naxa: pode parecer condescendente, mudei o texto.
Fred Foo
142

Embora eu concorde que a resposta aceita geralmente é a melhor solução e definitivamente mais fácil de usar, percebi que ninguém exibiu o uso adequado do iterador. Então, aqui está um exemplo rápido:

Iterator<Object> it = arrayList.iterator();
while(it.hasNext())
{
    Object obj = it.next();
    //Do something with obj
}
NemesisX00
fonte
12
Acho que isso responde com mais precisão à pergunta, já que é um exemplo de iterador em vez de uma solução alternativa.
aula de
1
Obrigado por sua resposta perspicaz. pois (...) iteração é geralmente a melhor solução, mas nem sempre. Hoje, estou procurando uma sintaxe de iterador explicitamente gerenciada e aqui está.
Robert Altman
37
List<String> arrayList = new ArrayList<String>();
for (String s : arrayList) {
    if(s.equals(value)){
        //do something
    }
}

ou

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

Mas tenha cuidado, ArrayList pode conter valores nulos . Portanto, a comparação deve ser

value.equals(arrayList.get(i))

quando tiver certeza de que o valor não é nulo ou você deve verificar se determinado elemento é nulo.

Zacheusz
fonte
10

Você também pode usar desta forma:

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

É uma boa prática lançar e usar o objeto. Por exemplo, se 'arrayList' contém uma lista de objetos 'Object1'. Então, podemos reescrever o código como:

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

Você também pode fazer um loop for como faria para um array, mas em vez de array [i], você usaria list.get (i)

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

Além da resposta de larsmans (que de fato está correta), a exceção em uma chamada para um método get (), então o código que você postou não é o que está causando o erro.

SJuan76
fonte
4

Maneira eficiente de iterar seu ArrayListseguido por este link . Este tipo irá melhorar o desempenho do loop durante a iteração

int size = list.size();

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

iterar usando o iterador não é seguro contra falhas, por exemplo, se você adicionar um elemento à coleção após a criação do iterador, ele lançará concurrentmodificaionexception. Além disso, não é thread-safe, você deve torná-lo thread-safe externamente.

Portanto, é melhor usar for-each estrutura de loop for. É pelo menos à prova de falhas.

Sumit Kumar Saha
fonte