ArrayList - Melhor maneira de percorrer

Tenho um arraylist que contem dados obtidos do banco de dados

ArrayList<ContatoT> contatos = ...;

ae eu quero percorrer o arraylist e imprimir o nome dos contatos

Entre os dois métodos abaixo, há diferença de performance? Pois acho o método 02 MUITO mais legível

Método-01

for (Iterator iterator = contatos.iterator(); iterator.hasNext(); ) { ContatoT c = (ContatoT) iterator.next(); System.out.println (c.getNome()); }

Método-02

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

1 curtida

assintoticamente, a performance sera a mesma. mas a segunda maneira vai ter uma performance MUITO pior se fosse uma LinkedList, por isso é recomendado sempre usarmos o Iterator quando percorremos uma List, ja que nao sabemos sua real implementacao.

Voce pode usar o enhanced for para melhor legibilidade, que vai acabar usando o iterator:


for(ContatoT c : contatos) {
  System.out.println(c.getNome());
}
2 curtidas

O método 2 é mais legível? :shock:
Isso é legível:

for(ContatoT contato : listaContatos){ System.out.println (contato.getNome()); }
E sobre a performance, utilizar Iterator é ligeiramente mais lento ( a diferença em geral é mais por preciosismo do que realismo ), mas gera menos perigo e trabalho do que trabalhar com array puro.

Até!

Obs.: não vi que o Paulo tinha respondido, mas já tinha apertado o botao e não tinha resposta.

Aquele cast ali é desnecessário no método 1. Basta criar o iterator como um Iterator<ContatoT>, já que sua lista é de ContatoT:

for (Iterator<ContatoT> iterator = contatos.iterator(); iterator.hasNext(); ) {
   ContatoT c = iterator.next();
   System.out.println (c.getNome());
} 

Outro comentário. Se você for excluir elementos enquanto percorre o ArrayList, será obrigado a usar o iterator e excluir através dele, ou então receberá um ConcurrentModificationException.

Exemplo que funciona:

public void apagaPorNome(String nome) { Iterator<ContatoT> it = contatos.iterator(); while (it.hasNext()) { ContatoT contato = it.next(); if (contato.getNome().startsWith(nome)) it.remove(); //Única forma de remover enquanto percorre } }

Exemplo que dá erro:

public void apagaPorNome(String nome) { for (ContatoT contato : contatos) { if (contato.getNome().startsWith(nome)) contatos.remove(contato); //Vai fazer o for gerar um ConcurrentModificationException } }

Outra dica. Ao postar códigos, use a tag code. É o que está fazendo essa formatação bonitinha nos nossos códigos. Isso nos ajuda a entender melhor o seu problema. Se não sabe ou tem dúvidas de como fazer isso, por favor, leia o tópico:
http://www.guj.com.br/posts/list/50115.java

2 curtidas

Opa, agradeço as resposta de todos

E… Nossa, no fim há 04 maneiras de percorrer a lista

Método 01

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

Método 02

for (Iterator iterator = contatos.iterator(); iterator.hasNext(); ) { ContatoT c = iterator.next(); System.out.println (c.getNome()); }

Método 03

for(ContatoT c : contatos) { System.out.println(c.getNome()); }

Método 04

Iterator<ContatoT> it = contatos.iterator(); while (it.hasNext()) { ContatoT c = it.next(); System.out.println(c.getNome()); }

Vamos ao que eu acho que entendi:

Método 01 - Só poderia ser considerado se fosse um arraylist, demais tipos de coleções deve-se usar iteratos
Método 02 - “for” usando iterator
Método 03 - Seria o “for each”/“enchanced for”, introduzido no java 1.5, onde o iterator fica implicito
Método 04 - Usando while(Este método achei o mais “feio” de todos)

Estas minhas considerações estao certas?

Outras dúvidas:
-existe diferença de performance entre os métodos 02 e 03?
-viniGodoy, poderia explicar o porquê do erro “ConcurrentModificationException” no exemplo que vc deu?

public void apagaPorNome(String nome) { for (ContatoT contato : contatos) { if (contato.getNome().startsWith(nome)) contatos.remove(contato); //Vai fazer o for gerar um ConcurrentModificationException } }

venom

A diferença de performance vai ser alguns microsegundos por iteração. A não ser que a sua lista tenha mais do que 1 milhão de objetos eu não me preocuparia com performance e usaria o modo mais claro.

Usando um iterator vc leaka iterator. Até o NIO Selector do Java faz isso (e leaka Integers tb). Isso sobrecarrega o GC. Talvez introduza 2 ms de latência no seu programa. Provavelmente vc pode viver sem esses 2 ms.

Se fosse LinkedList, aí eu te recomendaria usar o Iteartor sem dúvida, devido a diferença entre ArrayList e LinkedList.

Entre os metodos 2 e 3 nao há diferenca alguma, ja que o compilador troca a sinaxe do enhanced for por um iterator…

É simples.

Considere o risco de um iterator que não faz isso. Você itera até a penultima posição. Então, paralelamente, alguém (que pode ser seu próprio método de exclusão) vai lá e exclui 2 registros. Logo depois, você tenta avançar uma posição. Lembre-se: seu iterator não sabe que os registros foram excluídos, nem quais foram. O que acontece? Você provavalmente cairia num IndexOutOfBounds. Fora isso, o iterator poderia, sem saber, ter uma posição “pulada” e acabar não fazendo o comportamento esperado. Por exemplo, você está excluindo todos os 3 “João” da sua lista ordenada. Após excluir o primeiro, algum outro trecho do programa exclui uma “Ana”. O iterator do João, acaba ficando posicionado no último João (já que a Ana vem antes do João, o que fez todos os elementos posteriores voltarem uma posição), pulando o João do meio, e seu método simplesmente não realiza aquela exclusão. Inconsistente, não?

Por isso, o iterator faz uma verificação e não navegará mais se exclusões forem feitas paralelamente.

A maneira “segura” de se excluir enquanto se percorre uma lista é através do Iterator. Assim, ele fica sabendo não só que houve uma exclusão, mas também quem foi excluído e se é ou não possível continuar iterando.

Em alguns métodos, onde você só precisa de informação filtrada, as vezes é mais fácil fazer uma cópia da lista. Aí você itera pela lista original, e exclui objetos da cópia. A performance disso não é maravilhosa, mas é extremamente simples de se implementar, gera um código limpo e bastante válido para listas pequenas.

PS: Existem listas que tem Iterators mais espertos no pacote java.util.concurrent. Se você realmente precisar de uma lista com acessos em paralelo, use as listas desse pacote.