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.