"Olá, amigo!"

"Oi, Ellie!"

"Hoje eu quero falar sobre iteradores."

"Os iteradores foram inventados praticamente ao mesmo tempo que as coleções. O principal objetivo das coleções é armazenar elementos, e o principal objetivo de um iterador é recuperar esses elementos um por um."

"O que há de tão difícil em obter um conjunto de elementos?"

"Primeiro, os elementos em algumas coleções, como Set, não têm uma ordem estabelecida e/ou a ordem muda constantemente."

"Segundo, algumas estruturas de dados podem armazenar objetos de uma forma muito complexa: em diferentes grupos, listas, etc. Em outras palavras, distribuir todos os elementos em ordem seria uma tarefa nada trivial."

"Terceiro, as coleções tendem a mudar. Suponha que você decida exibir todo o conteúdo de uma coleção, mas bem no meio da saída a JVM muda para outro thread que substitui metade dos elementos da coleção. Então, em vez da saída, você obtém quem sabe o quê."

"Hum..."

"Mas! Esses são precisamente os tipos de problemas que um iterador pode resolver. Um iterador é um objeto especial dentro de uma coleção que, por um lado, tem acesso a todos os seus dados privados e conhece sua estrutura interna e, por outro lado, , implementa a interface pública Iterator, que permite que todos saibam como trabalhar com ela. "

"Alguns iteradores têm uma matriz interna na qual todos os elementos da coleção são copiados quando o iterador é criado. Isso garante que quaisquer alterações subsequentes na coleção não afetem o número ou a ordem dos elementos."

"Acho que você se deparou com isso ao trabalhar com for each . Não é possível fazer um loop simultâneo em uma coleção e remover elementos dela. Tudo isso é precisamente por causa da maneira como um iterador funciona."

"Nas novas coleções adicionadas à biblioteca de simultaneidade, o iterador foi reformulado para eliminar esse problema."

"Deixe-me lembrá-lo de como um iterador funciona."

"Java tem uma interface Iterator especial. Aqui estão seus métodos:"

Métodos da interface Iterator<E> Descrição
boolean hasNext() Verifica se há mais elementos
E next() Retorna o elemento atual e move para o próximo.
void remove() Remove o elemento atual

"Um iterador permite que você obtenha sucessivamente todos os elementos de uma coleção. É mais lógico pensar em um iterador como algo como um InputStream — ele tem todos os dados, mas sua tarefa é produzi-los sequencialmente."

"O   método next () retorna o próximo elemento da coleção."

"O método hasNext () é usado para verificar se há mais elementos."

"E remove () remove o elemento atual."

"Alguma pergunta?"

"Por que os métodos têm nomes tão estranhos? Por que não isEmpty() e getNextElement()?"

"Isso não faria mais sentido?"

"Faria mais sentido, mas os nomes vieram da linguagem C++, onde os iteradores apareceram antes."

"Entendo. Vamos continuar."

"Além de um iterador, existe também a interface Iterable, que deve ser implementada por todas as coleções que suportam iteradores. Possui um único método:"

Métodos da interface Iterable<T> Descrição
Iterator<T>iterator() Retorna um objeto iterador

"Você pode usar este método em qualquer coleção para obter um objeto iterador para percorrer seus elementos. Vamos percorrer todos os elementos de um TreeSet :"

Exemplo
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}

"Usar um iterador como este não é muito conveniente - há muito código supérfluo e óbvio. A situação ficou mais simples quando o loop for-each apareceu em Java."

"Agora este código é muito mais compacto e legível:"

Antes Depois
TreeSet<String> set = new TreeSet<String>();
Iterator<String> iterator = set.iterator();

while (iterator.hasNext())
{
 String item = iterator.next();
 System.out.println(item);
}
TreeSet<String> set = new TreeSet<String>();

for(String item : set)
{
 System.out.println(item);
}

"Este é o mesmo código! O iterador é usado em ambos os casos."

"É só que seu uso está oculto no loop for-each . Observe que o código à direita não tem nenhum texto em vermelho . O uso do iterador está completamente oculto."

"Um loop for-each pode ser usado para qualquer objeto que suporte iteradores. Em outras palavras, você pode escrever sua própria classe, adicionar o método iterator () a ela e usar seus objetos em uma construção for-each ."

"Uau! Claro, não estou ansioso para escrever minhas próprias coleções e iteradores, mas a perspectiva ainda é tentadora. Vou anotar isso."

Além disso, há outro tipo popular de iterador que possui até sua própria interface. Estou falando de um iterador para listas, ou seja, ListIterator .

"Independentemente de sua implementação, as listas mantêm a ordem dos elementos, o que torna o trabalho com elas por meio de um iterador um pouco mais conveniente."

"Aqui estão os métodos da interface ListIterator <E>:"

Método Descrição
boolean hasNext() Verifica se há mais elementos à frente.
E next() Retorna o próximo elemento.
int nextIndex() Retorna o índice do próximo elemento
void set(E e) Altera o valor do elemento atual
boolean hasPrevious() Verifica se há algum elemento atrás.
E previous() Retorna o elemento anterior
int previousIndex() Retorna o índice do elemento anterior
void remove() Remove o elemento atual
void add(E e) Adiciona um elemento ao final da lista.

"Em outras palavras, aqui podemos avançar e retroceder. E há alguns outros pequenos recursos."

"Bem, isso é interessante. Onde é usado?"

"Suponha que você queira mover para frente e para trás em uma lista vinculada. A operação get será bastante lenta, mas a operação next() será muito rápida."

"Hmm. Você me convenceu. Vou manter isso em mente."

"Obrigado, Ellie!"