Bom dia,
Alguém sabe a vantagem de usar Iterator ao invés de um for normal para percorrer um List?
Obrigado,
Nadilson
Bom dia,
Alguém sabe a vantagem de usar Iterator ao invés de um for normal para percorrer um List?
Obrigado,
Nadilson
Pra dizer que java é difícil…
Abraços.
Iterator é um padrão para percorrer listas, conjuntos, mapas etc.
É o que você chamaria de “cursor” se estivesse escrevendo stored procedures em algum banco SQL. Portanto não é um conceito novo ou extraordinariamente difícil de manipular.
Se você sabe que o seu List é um ArrayList, então não há problemas em usar o índice em vez de usar um Iterator. Para todos os outros tipos (LinkedList, Set, Map etc.) você tem de usar o Iterator.
E de qualquer maneira você continua a usar o for:
// digamos que coleção seja uma coleção de BlaBleBli
for (Iterator it = colecao.iterator(); it.hasNext(); ) {
BlaBleBli obj = (BlaBleBli) it.next();
}
Em Java 5, o “iterator” pode até ficar escondido:
for (BlaBleBli obj : colecao) {
}
Por exemplo se vc usar uma LinkedList com objetos nao ordenados o for get(i) percorrerá toda lista para encontrar tal objeto qnto ao Iterator buscara esse objeto de forma mais rápida pulando de nó em nó …
Agora qnto ao ArrayList usando o iterator ou for nao sei se faz diferença…
Eu nao tinha pensado nesta possibilidade… sempre associei Iterator - while.
Quer dizer entao que o iterator melhora a performace para Collections nao ordenados… interessante.
Obrigado a todos pela colaborãção.
Nadilson
Outra vantagem é que, a menos que você tenha uma lista imodificável, o Iterator permite que você remova um objeto enquanto está percorrento a lista.
Por exemplo:
while (it.hasNext)
{
obj = it.next();
if (canExclude(obj))
it.remove();
}
Você tem a garantia que o Iterator não vai se perder nos índices. Ele também vai remover da melhor forma possível.
No caso do LinkedList, faz diferença usar o iterator. A cada get() a LinkedLIst vai até o primeiro nó e então pula de nó em nó em busca de um elemento. No caso do iterator, ele só “desloca o ponteiro”.
No caso do Java 5, você pode substituir o iterator pelo for each sem prejuízo. A menos é claro, que queira excluir elementos.
Tem também o esquema que o ArrayList e Vector implementão RandomAccess. Tornando mais rápido usar um for() do o Iterator. Mas se o ArrayList e Vector tiverem um tamanho meio que grande, eles tem acesso linear, dai é melhor usar um Iterator.
Só não saquei porque isso acontece???
ViniGodoy, o que esse “canExclude()” verificaria??? Não rola um ConcurrentModificationException quando você tenta excluir um index da Collection enquanto estiver na interação??? o que eu sempre faço é marcar esse cara para deleção, e assim que sair da interação, excluir ele por fora.
[quote=Bateramos]Tem também o esquema que o ArrayList e Vector implementão RandomAccess. Tornando mais rápido usar um for() do o Iterator. Mas se o ArrayList e Vector tiverem um tamanho meio que grande, eles tem acesso linear, dai é melhor usar um Iterator.
Só não saquei porque isso acontece???
ViniGodoy, o que esse “canExclude()” verificaria??? Não rola um ConcurrentModificationException quando você tenta excluir um index da Collection enquanto estiver na interação??? o que eu sempre faço é marcar esse cara para deleção, e assim que sair da interação, excluir ele por fora.[/quote]
Se usar um iterador não dá exceção. Essa é a vantagem. É mais eficiente e seguro que um mecanismo de marcação.
A função canExclude é uma função imaginária que verificaria se o elemento deve ser excluido.
Embora ArrayList implemente RandomAccess vc não deve colocar isso na assinatura dos seus métodos, deve ser usar apenas List.
Mas ai vc não sabe mais se implementa RandomAcces ou não, então é mais seguro usar o iterador, ou vc se arrisca a usar get(index) num LinkedList e ter a performance do seu método indo pelo cano. Ha poucas ocasiões onde vc precisa de um RandomAcess e é na ordenação com Collections.sort() , fora isso, não ha muitas razões para usar for sem iterador. Aliás, for sem iterator é um sinal de codigo feito por amadores/juniors e é preciso que esteja documentado corretamente se essa for a implementação necessária para o caso. Caso contrário é um erro de codificação.
Levem a mal a reabertura da thread não, mas é porque não entendi essa afirmação:
Porque?
Quer dizer que essa implementação é incorreta?
for(int i= 0; i<=x; i++) {
//...
}
não é incorreta.
Para navegar por um array, levando em conta que X é o legth do array… tá de boa esse código, sussa!
Mas para Collection… tipo List ou Set, é melhor usar um iterator, que você consegue remover e ditar os elementos sem grandes problemas
[quote=xdraculax]Levem a mal a reabertura da thread não, mas é porque não entendi essa afirmação:
Porque?
Quer dizer que essa implementação é incorreta?
for(int i= 0; i<=x; i++) {
//...
}
[/quote]
Dependendo do que está dentro do for sim.
se vc faz codigo assim:
List lista = .. .
for(int i= 0; i<=x; i++) {
lista.get(i);
}
Então sim. Isso é totalmente proibitivo se a lista for um LinkedList. ( É por isso que todo o mundo só usa arraylist com a desculpa que é mais eficiente fazer o for. Não é. O for com iterator do linkelist é mais eficiente - porque não usa nenhuma variável de controle)
No java 5 e depois , ha muito poucas razões para usar iteração com inteiros.
Mesmo com arrays vc pode usar o for estendido. E nesse caso o uso de iterator é apenas para quando quer usar o remove().
Não é mais eficiente pois a lista não representa uma estrutura contínua de memória, enquanto o ArrayList, sim. Entretanto, esse é o tipo de otimização de microcódigo que, a menos que você faça MUITAS operações em listas, ou use listas MUITO grandes, jamais notará uma diferença de performance significativa.
De qualquer forma, hoje em dia não há muitas razões para não usar o for each, como o próprio sergio ressaltou. A única que vejo é se você precisar excluir elementos no processo, o que já te obrigaria a usar um Iterator de um jeito ou de outro.
Só para explicar mais o que o Sergio falou.
Em linked lists o método get precisa obrigatóriamente percorrer a lista até o n-ézimo elemento. Podemos imaginar que a implementação dele segue o seguinte algoritmo:
public T get(int index) {
Node<T> node = getFirst();
for (int i = 0; i < index; i++)
node = node.next();
return node.getValue();
}[/code]
Perceba que fazer o for usando o get irá disparar aquele for interno várias vezes. Já na implementação com o iterator isso não ocorre. O iterator provavelmente é implementado mais ou menos assim:
[code]public class LinkedListIterator<T> implements Iterator<T>
{
private Node<T> node;
private bool beforeFirst;
private LinkedListIterator(Node<T> first) {
this.node = first;
}
@override
public bool hasNext() {
return node != null;
};
@override
public T next() {
if (beforeFirst) {
beforeFirst = false;
return node.getValue();
}
node = node.next();
return node.getValue();
}
}
Note que aqui, cada chamada ao next apenas avança um item da lista. Não existe um for inteiro, percorrendo a lista do zero até aquele item. Como muitas vezes você percorre a lista através da interface List, você não tem como garantir se a lista sendo percorrida é ou não um arraylist. Por isso, a iteração por coleções usando índice é inteiramente desaconselhada.
Então, se eu uso o for, e dentro do for eu acesso o elemento de uma LinkedList pelo índice, significa que na execução do get, a iteração vai percorrer todos os elementos da LinkedList até o índice da iteração atual do MEU loop, correto?
Estou perguntando porque já vi isso em uns códigos aqui, e não reparei nisso.
Quando vou fazer iteração com loop (se for um ArrayList) eu uso o:
for( Tipo t: coleção){…}
Nesse caso, ele use o iterator para percorrer os elementos da lista?
Sim, o for each usa o iterator automaticamente.
É isso mesmo, cada get que você dá num linked list, ele percorre do início até a posição do get. Isso dentro de um for transforma o método em algo de performance catrastrófica.
Para o ArrayList não existe esse problema, nem com índices, nem com o iterator, já que o ArrayList é implementado através de um array e um get pode simplesmente retornar aquela posição do vetor.
[quote=xdraculax]Então, se eu uso o for, e dentro do for eu acesso o elemento de uma LinkedList pelo índice, significa que na execução do get, a iteração vai percorrer todos os elementos da LinkedList até o índice da iteração atual do MEU loop, correto?
Estou perguntando porque já vi isso em uns códigos aqui, e não reparei nisso.
Quando vou fazer iteração com loop (se for um ArrayList) eu uso o:
for( Tipo t: coleção){…}
Nesse caso, ele use o iterator para percorrer os elementos da lista?[/quote]
Sim. Mas veja que na realidade o for extendido é uma operação especial do compilador.
Ele compila codigo diferente conforme o objeto iterado é um array ou um Iterable. qualquer Iterable pode ser usado, não apenas Collection e Map e suas filhas. Vc pode criar objetos que são naturalmente compostos e iterálos facilmente, exemplo
for (ItemPedido item : pedido ){
}
no caso aqu teriamos a classe Pedido que implementa Iterable
Entendi, obrigado pela ótima explicação :):):).
Só uma nota: então, as implementações de estruturas de dados como LinkedList não deveriam ter um método de obtenção por índice (como o get), e sim somente hasNext() e next().
E por que não? Você pode, efetivamente, querer pegar o segundo elemento da lista uma única vez:
public Car segundoLugar = finalistas.get(2);
Não é a operação mais rápida do mundo num LinkedList, mas é uma operação possível em listas. Se for feita esporadicamente, ou em listas menores, não compromete a performance.
Mas por isso, quando você vai utilizar collections, é importante conhecer bem as características de cada uma delas. Especialmente se você estiver trabalhando com otimização, seja de memória ou de velocidade.
Oi Thingol, por favor pode me explicar como assim todos os outros usam o iterator?
Oi Thingol/Vini, podem me explicar como assim todos usam o iterator?
abraço,
André AS