Por que a Iterator
interface não se estende Iterable
?
O iterator()
método poderia simplesmente retornar this
.
É de propósito ou apenas uma supervisão dos designers de Java?
Seria conveniente poder usar um loop for-each com iteradores como este:
for(Object o : someContainer.listSomeObjects()) {
....
}
onde listSomeObjects()
retorna um iterador.
Respostas:
Porque um iterador geralmente aponta para uma única instância em uma coleção. Iterable implica que se pode obter um iterador de um objeto para percorrer seus elementos - e não há necessidade de iterar em uma única instância, que é o que um iterador representa.
fonte
Um iterador é stateful. A idéia é que, se você ligar
Iterable.iterator()
duas vezes, obterá iteradores independentes - para a maioria dos iteráveis, de qualquer maneira. Isso claramente não seria o seu caso.Por exemplo, eu normalmente posso escrever:
Isso deve imprimir a coleção duas vezes - mas com o seu esquema o segundo loop sempre termina instantaneamente.
fonte
iterator
e usar o resultado, ele terá que repetir a coleção - o que não acontecerá se o mesmo objeto já tiver repetido a coleção. Você pode fornecer qualquer implementação correta (exceto para uma coleção vazia) em que o mesmo iterador é retornado duas vezes?iterable
duas vezes fornecerá iteradores independentes.Pelos meus US $ 0,02, concordo plenamente que o Iterator não deve implementar o Iterable, mas acho que o loop for aprimorado também deve aceitar. Eu acho que todo o argumento "torne os iteradores iteráveis" surge como uma solução para um defeito no idioma.
Todo o motivo da introdução do loop for aprimorado foi que "elimina a labuta e a propensão a erros dos iteradores e variáveis de índice ao iterar sobre coleções e matrizes" [ 1 ].
Por que, então, esse mesmo argumento não se aplica aos iteradores?
Nos dois casos, as chamadas para hasNext () e next () foram removidas e não há referência ao iterador no loop interno. Sim, entendo que os Iterables podem ser reutilizados para criar vários iteradores, mas isso acontece fora do loop for: dentro do loop, só há uma progressão para a frente um item de cada vez nos itens retornados pelo iterador.
Além disso, permitir isso também tornaria fácil o uso do loop for para enumerações, que, como foi apontado em outro lugar, são análogas a Iteradores e não Iterables.
Portanto, não faça o Iterator implementar Iterable, mas atualize o loop for para aceitar qualquer um.
Felicidades,
fonte
for(item : iter) {...}
sintaxe, ele provocará um erro quando o mesmo iterador for iterado duas vezes. Imagine queIterator
é passado paraiterateOver
método em vez deIterable
nos este exemplo .for (String x : strings) {...}
ouwhile (strings.hasNext()) {...}
: se você tentar percorrer um iterador duas vezes na segunda vez, não produzirá resultados, então não vejo isso por si só como um argumento contra permitir a sintaxe aprimorada. A resposta de Jon é diferente, porque ele está mostrando como envolver umIterator
em umIterable
causaria problemas, pois nesse caso você esperaria poder reutilizá-lo quantas vezes quiser.Como apontado por outros,
Iterator
eIterable
são duas coisas diferentes.Além disso, as
Iterator
implementações anteriores ao aprimoramento para loops.Também é trivial superar essa limitação com um método adaptador simples que se parece com isso quando usado com importações de métodos estáticos:
Exemplo de implementação:
No Java 8, adaptar um
Iterator
a umIterable
fica mais simples:fonte
for (String s : (Iterable<String>) () -> iterator)
Como já foi dito, um Iterable pode ser chamado várias vezes, retornando um Iterator novo a cada chamada; um iterador é usado apenas uma vez. Portanto, eles estão relacionados, mas servem a propósitos diferentes. Frustrantemente, no entanto, o método "compactar para" funciona apenas com um iterável.
O que descreverei abaixo é uma maneira de obter o melhor dos dois mundos - retornando um Iterável (para uma sintaxe mais agradável), mesmo quando a sequência de dados subjacente é única.
O truque é retornar uma implementação anônima do Iterable que realmente aciona o trabalho. Portanto, em vez de fazer o trabalho que gera uma sequência pontual e, em seguida, retornar um Iterator sobre isso, você retorna um Iterable que, cada vez que é acessado, refaz o trabalho. Isso pode parecer um desperdício, mas muitas vezes você chamará o Iterable de qualquer maneira e, mesmo que o chame várias vezes, ele ainda terá uma semântica razoável (ao contrário de um invólucro simples que faz com que um Iterador "pareça" um Iterável, isso é válido ' t falhar se usado duas vezes).
Por exemplo, digamos que eu tenho um DAO que fornece uma série de objetos de um banco de dados e desejo fornecer acesso a ele por meio de um iterador (por exemplo, para evitar a criação de todos os objetos na memória, se não forem necessários). Agora eu poderia simplesmente retornar um iterador, mas isso torna feio o uso do valor retornado. Então, em vez disso, envolvo tudo em um Iterable anon:
isso pode ser usado em código como este:
o que me permite usar o loop for compacto, mantendo o uso incremental de memória.
Essa abordagem é "preguiçosa" - o trabalho não é feito quando o Iterable é solicitado, mas somente mais tarde quando o conteúdo é repetido - e você precisa estar ciente das consequências disso. No exemplo com um DAO, isso significa iterar sobre os resultados na transação do banco de dados.
Portanto, existem várias advertências, mas isso ainda pode ser um idioma útil em muitos casos.
fonte
returning a fresh Iterator on each call
deve ser acompanhado com porque isto é para evitar problema de concorrência ...Incrivelmente, ninguém mais deu essa resposta ainda. Veja como você pode iterar "facilmente" sobre um
Iterator
usando o novoIterator.forEachRemaining()
método Java 8 :Obviamente, existe uma solução "mais simples" que trabalha diretamente com o loop foreach, envolvendo o
Iterator
in aIterable
lambda:fonte
Iterator
é uma interface que permite iterar sobre algo. É uma implementação de percorrer uma coleção de algum tipo.Iterable
é uma interface funcional que indica que algo contém um iterador acessível.No Java8, isso facilita bastante a vida ... Se você tem um,
Iterator
mas precisa de um,Iterable
pode simplesmente fazer:Isso também funciona no loop for:
fonte
Concordo com a resposta aceita, mas quero adicionar minha própria explicação.
O iterador representa o estado do deslocamento, por exemplo, você pode obter o elemento atual de um iterador e avançar para o próximo.
Iterable representa uma coleção que pode ser percorrida, pode retornar quantos iteradores você desejar, cada um representando seu próprio estado de deslocamento, um iterador pode estar apontando para o primeiro elemento, enquanto outro pode estar apontando para o terceiro elemento.
Seria bom se o Java for loop aceite o Iterator e o Iterable.
fonte
Para evitar dependência do
java.util
pacoteDe acordo com o JSR original, Um loop for aprimorado para a Java ™ Programming Language , as interfaces propostas:
java.lang.Iterable
java.lang.ReadOnlyIterator
(proposto para ser adaptado
java.util.Iterator
, mas aparentemente isso nunca aconteceu)… Foram projetados para usar o
java.lang
namespace do pacote em vez dejava.util
.Para citar o JSR:
A propósito, o antigo
java.util.Iterable
ganhou um novoforEach
método no Java 8+, para uso com a sintaxe lambda (passando aConsumer
).Aqui está um exemplo. A
List
interface estende aIterable
interface, como qualquer lista carrega umforEach
método.fonte
Eu também vejo muitos fazendo isso:
Mas isso não faz tudo certo! Este método não seria o que você deseja!
O método
iterator()
deve retornar um novo iterador começando do zero. Então é preciso fazer algo assim:A questão é: haveria alguma maneira de fazer uma classe abstrata realizando isso? Para que um IterableIterator seja necessário, basta implementar os dois métodos next () e hasNext ()
fonte
Se você veio aqui em busca de uma solução alternativa, pode usar IteratorIterable . (disponível para Java 1.6 e superior)
Exemplo de uso (reversão de um vetor).
impressões
fonte
Por uma questão de simplicidade, Iterator e Iterable são dois conceitos distintos, Iterable é simplesmente uma abreviação de "Posso retornar um Iterador". Eu acho que seu código deve ser:
com alguma instânciaContainer
SomeContainer extends Iterable<Object>
fonte
Como um aparte: Scala tem um método toIterable () no Iterator. Veja a conversão implícita ou explícita de scala de iterador para iterável
fonte
Em uma nota relacionada, você pode encontrar o adaptador IteratorIterable no Apache Commons Collections4 útil. Basta criar uma instância a partir de um iterador e você terá o iterável correspondente.
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/iterators/IteratorIterable.html
O JavaScript é necessário para o funcionamento completo desta página.
fonte
Os iteradores são stateful, eles têm um "próximo" elemento e ficam "exaustos" depois de iterados. Para ver onde está o problema, execute o código a seguir, quantos números são impressos?
fonte
Você pode tentar o seguinte exemplo:
fonte