For, foreach ou Iterator() - pq?

[quote=andredecotia]oi gente,
o q tem a dizer sobre o for, foreach ou Iterator(), o q usariam e pq? aliás há algo em relação à performance do código se usar
um ou outro?

fiz um pequeno teste, usando os três:

[code]static public List listaNome(){
List lista = new ArrayList();
lista.add(“André”);
lista.add(null);
lista.add(“Gatinha”);
lista.add(null);
lista.add(null);
lista.add(null);
lista.add(null);

	/*for (int i = 0; i < lista.size(); i++) {
		System.out.println(lista.get(i));;
	}*/
	
	
	
	/*for (String string : lista) {
		System.out.println(lista);
	}*/
	
	
	
	 for (Iterator<String> it = lista.iterator(); it.hasNext(); ) {  
	    while(it.hasNext()){
	    	System.out.println(it.next());
	    }
	}
	return lista;
}[/code][/quote]

Por que vc usa duas vezes it.hasNext no iterator e um for junto com o iterator?

o foreach usa o iterator, vc so pode usar foreach em objetos que são “Iteraveis”

Não muda nada usar um ou outro, use o que vc achar melhor.

[quote=andredecotia]oi gente,
o q tem a dizer sobre o for, foreach ou Iterator(), o q usariam e pq? aliás há algo em relação à performance do código se usar
um ou outro?

fiz um pequeno teste, usando os três:

[code]static public List listaNome(){
List lista = new ArrayList();
lista.add(“André”);
lista.add(null);
lista.add(“Gatinha”);
lista.add(null);
lista.add(null);
lista.add(null);
lista.add(null);

	/*for (int i = 0; i < lista.size(); i++) {
		System.out.println(lista.get(i));;
	}*/
	
	
	
	/*for (String string : lista) {
		System.out.println(lista);
	}*/
	
	
	
	 for (Iterator<String> it = lista.iterator(); it.hasNext(); ) {  
	    while(it.hasNext()){
	    	System.out.println(it.next());
	    }
	}
	return lista;
}[/code][/quote]

Isso vai da preferência. Creio que não tem diferença na performance entre eles não!
Eu, particularmente, uso a segunda maneira, sempre.

Pra que esse while :shock:

for (Iterator<String> it = lista.iterator(); it.hasNext(); ) { while(it.hasNext()){ System.out.println(it.next()); } }

Resumidamente, a diferença é essa:

for:
Serve para iterar em arrays e listas, pois eles permitem o acesso a elementos por índice.

iterator:
Usado para iterar em qualquer tipo de coleção, pois todas implementam o iterator(). Não serve para arrays.

foreach:
É apenas uma conveniência da linguagem, o compilador automaticamente transforma em um dos dois acima dependendo se é Array ou Coleção.

Hoje em dia o mais prático é sempre usar o foreach, a não ser que precise de alguma coisa específica como por exemplo:

for(int i = 0; i < array.length; i++) { // Faz alguma coisa que precisa do valor de i }

Utilizo o foreach quando não há a necessidade de alterar os valores da coleção ou array e o for tradicional quando há necessidade. Mas todos realizam a iteração, portanto, se esta for sua única necessidade, utilize qualquer uma das opções.

O for each usa os iterators. É através dele que ele faz a iteração.

Não há nenhum benefício em usar o iterator diretamente hoje em dia, a menos que você queira excluir elementos da sua coleção enquanto itera. Por exemplo, excluir todos os “Vinicius” da lista:

Iterator<String> it = lista.iterator(); while (it.hasNext()) { String nome = it.next(); if ("Vinícius".equals(nome)) { it.remove(); //Remove o elemento } }

Fazer a iteração com o for simples quase nunca é desejável. Existe uma diferença brutal de performance em algumas coleções. Por exemplo, o método get do LinkedList é implementado dessa forma (é um pseudo-código):

[code]public T get(int index) {
if (index == 0)
return cabeça.getValue();

No no = cabeça;
int cont = 0;
while (cont < index && no != null) {
    no = no.getProximo();
}
return index < cont ? null : no.getValue();

}[/code]

Como vcs podem ver, o método get é obrigado a percorrer a lista toda para obter o nó que está num determinado índice. Isso porque o linkedlist, como o próprio nome indica, é uma lista ligada e seus elementos não encontram-se indexados. Por isso, um for como esse:

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

É, na verdade, dois for aninhados. Isso aí irá realizar N*N! saltos para percorrer todos os elementos da lista.

Com o iterator, esse código é muitíssimo mais eficiente. O iterator simplesmente guarda o nó atual, e facilmente avança para o próximo nó. Ou seja, para percorrer N elementos, ele faz N saltos. Há poucos dias atrás, um usuário aqui do GUJ comparou a performance das duas listas: http://www.guj.com.br/posts/list/217173.java#1108931

Veja ali que ele nem sequer teve paciência para esperar a iteração com for simples, no caso da LinkedList.

Em resumo:
for -> Quase nunca deve ser usado para iterar coleções. A exceção são os arrays primitivos, se eventualmente vc precisar do valor de i.
for each -> Use sempre que puder
iterator -> Use sempre que for excluir enquanto itera.

1 curtida

[quote=gomesrod]Resumidamente, a diferença é essa:

for:
Serve para iterar em arrays e listas, pois eles permitem o acesso a elementos por índice.

iterator:
Usado para iterar em qualquer tipo de coleção, pois todas implementam o iterator(). Não serve para arrays.

foreach:
É apenas uma conveniência da linguagem, o compilador automaticamente transforma em um dos dois acima dependendo se é Array ou Coleção.

Hoje em dia o mais prático é sempre usar o foreach, a não ser que precise de alguma coisa específica como por exemplo:

for(int i = 0; i < array.length; i++) { // Faz alguma coisa que precisa do valor de i }[/quote]

Foreach nao serve pra arrays? Tem certeza?

por favor, pode me dar um exemplo de como implementaria esse iterator sem usar o for?

Ueh, tem no post logo acima ai do Vini

Aliás, eu prefiro evitar fors que não sejam “tradicionais”. É possível fazer fors rebuscados, mas geralmente levam a um código um tanto confuso. Pra que complicar se dá pra simplificar?

Iterator it = lista.iterator(); while (it.hasNext()) { String nome = it.next(); System.out.println(nome); }

A única vantagem daquele for sobre esse while é que o escopo da variável it é menor. A sintaxe certa seria assim:

for (Iterator<String> it = lista.iterator(); it.hasNext(); ) { String nome = it.next(); System.out.println(nome); }

Sem um while dentro.

[quote=evertonsilvagomesjava][quote=gomesrod]
(…)
o compilador automaticamente transforma em um dos dois acima dependendo se é Array ou Coleção.
(…)

for(int i = 0; i < array.length; i++) { // Faz alguma coisa que precisa do valor de i }[/quote]

Foreach nao serve pra arrays? Tem certeza?[/quote]
Eu tenho certeza que serve! Como coloquei na frase anterior.

Talvez não tenha sido bastante claro, mas o que o exemplo queria mostrar foi: o FOR deve ser usado quando você precisa do valor de i para alguma coisa além de recuperar os elementos do array ou lista.

Foi isso que eu quis dizer:

Eu ainda tiro fora o “ou lista”. Para lista é melhor usar o for each, e usar um contador incrementado por você:

int i = 0; for (String x : strings) { ... i++; }

Justamente por causa que você nunca tem certeza se a lista em questão não é uma LinkedList, de performance horrível no get.

Você pode optar por não utilizar o for each para manter a compatibilidade do fonte com o JDK 1.4 :slight_smile:

Isso pode ocorrer se você tem dois clientes de uma mesmo sistema que possui infra estrutura diferentes.

[quote=PedroTOliveira]Você pode optar por não utilizar o for each para manter a compatibilidade do fonte com o JDK 1.4 :slight_smile:

Isso pode ocorrer se você tem dois clientes de uma mesmo sistema que possui infra estrutura diferentes.[/quote]

Um detalhe interessante é que é possível manter compatibilidade dos binários usando for each e os generics. Você pode pedir para o java compilar os .class levando em consideração que a sua VM é 1.4, e ainda usar esses recursos.

[quote=PedroTOliveira]Você pode optar por não utilizar o for each para manter a compatibilidade do fonte com o JDK 1.4 :slight_smile:

Isso pode ocorrer se você tem dois clientes de uma mesmo sistema que possui infra estrutura diferentes.[/quote]
Nem me diga… recentemente passei por isso, depois do deploy nada funcionou porque os servidores usavam java 1.4
Maior correria para tirar os foreachs, generics, autobox…

Mas mesmo assim não acho uma boa idéia desenvolver com foco nesse tipo de situação, afinal toda a evolução da linguagem será desperdiçada!

[quote=ViniGodou]
Eu ainda tiro fora o “ou lista” (…)[/quote]
Tá certo… Anotado! 8)

Nem me diga… recentemente passei por isso, depois do deploy nada funcionou porque os servidores usavam java 1.4
Maior correria para tirar os foreachs, generics, autobox…[/quote]

Você tentou compilar em modo de compatibilidade? Eu compilei várias vezes assim, e funciona perfeitamente. Os generics fazem erasure na compilação, ou seja, não existem no bytecode. O mesmo vale para AutoBoxing. O for each é traduzido para os iterators. Acho que o único recurso realmente novo é o enum, ainda assim, ele pode ser transformado numa classe com atributos estáticos, que é o que a compilação especial faz.

Para mim é novidade…

O que eu fiz foi colocar a opção Compiler Compliance Level para 1.4, mas aí os recursos não compatíveis ficam com erro de compilação e é preciso acertar um a um.

Você JURA que dá pra fazer automaticamente? :shock:

Nem me diga… recentemente passei por isso, depois do deploy nada funcionou porque os servidores usavam java 1.4
Maior correria para tirar os foreachs, generics, autobox…[/quote]

Você tentou compilar em modo de compatibilidade? Eu compilei várias vezes assim, e funciona perfeitamente. Os generics fazem erasure na compilação, ou seja, não existem no bytecode. O mesmo vale para AutoBoxing. O for each é traduzido para os iterators. Acho que o único recurso realmente novo é o enum, ainda assim, ele pode ser transformado numa classe com atributos estáticos, que é o que a compilação especial faz.[/quote]

É realmente.
Não havia lembrado desse detalhe. :slight_smile:

Edit:
Apesar que não consegui reproduzir aqui.

Voce poderia nos dar um exemplo Vini?

Sim, é só usar a opção -target do compilador:

javac SuaClasse.java -target 1.4

O “source” compliance level que as IDEs tem é realmente relacionado ao source code. Ele exige que você altere o fonte mesmo.

Não é o caso do target. Pode-se programar muito bem em Java 5, e compilar para java 4.
O que ele não conseguir compilar ele chia, mas não é nem 10% do que vcs passaram.

Gente adorei os posts… :lol:

Aproveitando o ensejo, o Vini falando tb sobre classpath… Será alguém consegueria me ajudar com esta questão aqui:

http://www.guj.com.br/posts/list/218370.java