1. Histórico de como os iteradores surgiram
Você já está familiarizado com HashSet
. Se você realmente investigou, além de apenas ler uma lição, deveria ter feito esta pergunta:
Como faço para exibir uma lista de todos os elementos HashSet na tela? Afinal, a interface não tem get()
e set()
métodos!
E HashSet
não está sozinho nessa limitação. Além de HashSet
, existem muitas outras coleções que não permitem que os elementos sejam recuperados pelo índice, pois os elementos não possuem ordem definida.
Ao longo dos anos, os programadores inventaram muitas estruturas de dados complexas, como gráficos e árvores. Ou listas de listas.
Muitos contêineres alteram a ordem de seus elementos quando novos elementos são adicionados ou elementos existentes são removidos. Por exemplo, uma lista armazena elementos em uma determinada ordem e, quando um novo elemento é adicionado, quase sempre é inserido no meio da lista.
E também temos situações em que há um contêiner que armazena elementos, mas não em uma ordem fixa.
Agora, digamos que queremos copiar todos os elementos de tal coleção para um array ou lista. Precisamos obter todos os elementos. Não nos importamos com a ordem em que iteramos sobre os elementos — o importante é não iterar sobre os mesmos elementos mais de uma vez. Como fazemos isso?
2. Iterador para uma coleção
Iteradores foram propostos como uma solução para o problema acima.
Um iterador é um objeto especial associado a uma coleção, que ajuda a percorrer todos os elementos da coleção sem repetir nenhum.
Você pode usar o seguinte código para obter um iterador para qualquer coleção:
Iterator<Type> it = name.iterator();
Onde name
é o nome da variável da coleção, Type
é o tipo dos elementos da coleção, iterator()
é um dos métodos da coleção e it
é o nome da variável do iterador.
Um objeto iterador tem 3 métodos:
Método | Descrição |
---|---|
|
Retorna o próximo elemento da coleção |
|
Verifica se existem elementos que ainda não foram percorridos |
|
Remove o elemento atual da coleção |
nextInt)
Esses métodos são um pouco semelhantes aos métodos e da classe Scanner hasNextInt()
.
O next()
método retorna o próximo elemento da coleção da qual obtivemos o iterador.
O hasNext()
método verifica se a coleção possui elementos adicionais que o iterador ainda não retornou.
Veja como exibir todos os elementos de um HashSet
:
Código | Notas |
---|---|
|
Crie um HashSet objeto que armazene String elementos. Adicionamos saudações em vários idiomas à set variável. Obtenha um objeto iterador para o set conjunto. Desde que ainda existam elementos Obtenha o próximo elemento Exiba o elemento na tela |
3. For-each
loop
A principal desvantagem de um iterador é que seu código se torna mais complicado do que usar um for
loop.
Para comparar, vamos exibir uma lista usando um for
loop e também usando um iterador:
Iterador | para loop |
---|---|
|
|
Sim, é muito melhor percorrer os elementos de um ArrayList
usando um loop — tudo fica mais curto.
Mas os criadores do Java novamente decidiram jogar um pouco de açúcar em nós. Felizmente para nós, era açúcar sintático .
Eles deram a Java um novo tipo de loop e o chamaram de for-each
loop. É assim que fica em geral:
for(Type name:collection)
Onde collection
é o nome da variável da coleção, Type
é o tipo dos elementos na coleção e name
é o nome de uma variável que obtém o próximo valor da coleção em cada iteração do loop.
Esse tipo de loop itera por todos os elementos de uma coleção usando um iterador implícito. É assim que realmente funciona:
Para cada loop | O que o compilador vê: Loop com um iterador |
---|---|
|
|
Quando o compilador encontra um for-each
loop em seu código, ele simplesmente o substitui pelo código à direita: ele adiciona uma chamada para obter um iterador junto com qualquer outra chamada de método ausente.
Os programadores adoram o for-each
loop e quase sempre o usam quando precisam iterar sobre todos os elementos de uma coleção.
Mesmo a iteração em uma ArrayList
lista usando um for-each
loop parece mais curta:
Para cada loop | para loop |
---|---|
|
|
4. Removendo um elemento em um for-each
loop
O for-each
loop tem uma desvantagem: não pode remover os elementos corretamente. Se você escrever um código como este, receberá um erro.
Código | Observação |
---|---|
|
A operação de remoção irá gerar um erro! |
Este é um código muito bom e compreensível, mas não funcionará.
Você não pode alterar uma coleção enquanto a percorre com um iterador.
Existem três maneiras de contornar essa limitação.
1. Use um tipo diferente de loop
When traversing an ArrayList collection
, você pode usar um loop comum com uma i
variável de contador.
Código |
---|
|
No entanto, esta opção não é adequada para HashSet
e HashMap
coleções
2. Use um iterador explícito
Você pode usar um iterador explicitamente e chamar seu remove()
método.
Versão que funciona | Versão que não funciona |
---|---|
|
|
Observe que chamamos o remove()
método no objeto iterador! O iterador está ciente de que o item foi removido e pode lidar com a situação corretamente.
3. Use uma cópia da coleção
Você também pode criar uma cópia da coleção e, em seguida, usar a cópia em um for-each
loop e excluir elementos da coleção original.
Código | Observação |
---|---|
|
Criar uma cópia de uma coleção é super fácil. O loop usa o iterador para a cópia da coleção. Os elementos são removidos da list coleção. |
A coleção é copiada rapidamente, pois os próprios elementos não são duplicados. Em vez disso, a nova coleção armazena referências aos elementos que já existem na coleção antiga.
GO TO FULL VERSION