Stream
herda um método iterator () para produzir um Iterator
.
Mas eu preciso de um Iterable
e não de um Iterator
.
Por exemplo, dada esta sequência:
String input = "this\n" +
"that\n" +
"the_other";
... Eu preciso passar essas partes da string como uma Iterable
para uma biblioteca específica. Chamar input.lines()
produz a Stream
. Então, eu estaria pronto se pudesse transformar isso Stream
em um Iterable
de seus elementos.
java
java-stream
iterable
Basil Bourque
fonte
fonte
Respostas:
Conforme explicado em Por que o Stream <T> não implementa Iterable <T>? ,
Iterable
tem a expectativa de poder fornecerIterator
mais de uma vez, o queStream
não pode atender. Portanto, embora você possa criar umIterable
out de umStream
para um uso ad-hoc, você deve ter cuidado para saber se existem tentativas de iterá-lo várias vezes.Como você disse: " Eu preciso passar essas partes da string como uma
Iterable
para uma biblioteca específica ", não há solução geral, pois o código que está usandoIterable
está fora do seu controle.Mas se você é quem criou o fluxo, é possível criar um válido
Iterable
que simplesmente repita a construção do fluxo sempre queIterator
for solicitado:Isso atende à expectativa de oferecer suporte a um número arbitrário de iterações, sem consumir mais recursos do que um único fluxo ao ser percorrido apenas uma vez.
fonte
Iterable<String> lines = "this\nthat\nthe_other".lines()::iterator;
esse é um daqueles casos raros em que uma referência de método não é a mesma que uma lambda e, de fato, teria efeito indesejável.expression::name
nunca são as mesmas que as expressões lambda, nem mesmo paraSystem.out::println
. Mas aqui, temos um dos casos em que isso importaStream<String> lines = str.lines();
você criar oIterable<String> iter = lines::iterator
versus()->lines.iterator()
.stream::iterator
e() -> stream.iterator()
. De fato, minha resposta disse com precisão, não há solução geral para converter um fluxo existente em um iterável válido que permita várias iterações. Repetir a construção do fluxo toda vez que um iterador é solicitado, ou seja, aqui significa chamarlines()
sempre, é o que faz a diferença.expression::name
significa " avaliarexpression
uma vez e capturar o resultado ", enquanto que() -> expression.name(…)
significa " avaliarexpression
cada vez que o corpo da função é avaliado ". As diferenças são pequenas quando "expression
" é apenas uma variável local, mas mesmo assim é diferente, ou seja,stream::iterator
se comportará de maneira diferente de() -> stream.iterator()
quandostream
énull
. Portanto, minha declaração ainda é válida,expression::name
sempre é diferente de uma expressão lambda, a questão é: quanto isso importa para o meu caso de uso específico.tl; dr
Basta lançar , não há necessidade de converter.
Transmitir
Stream < String >
paraIterable < String >
.Detalhes
CUIDADO Consulte Resposta de Holger, explicando os perigos do uso de um fluxo de backup
Iterable
.Sim, você pode fazer um
Iterable
de aStream
.A solução é simples, mas não óbvia. Veja este post no FAQ Lambda de Maurice Naftalin .
o
iterator()
método emBaseStream
(superclasse deStream
) retornandoIterator
a coincide com o mesmo nome doiterator()
método retornando aIterator
conforme exigido pelaIterable
interface. As assinaturas do método correspondem. Então, na verdade, podemos converterStream
para aIterable
, sem necessidade de conversão.Faça sua entrada.
Lance isso
Stream<String>
paraIterable<String>
.Teste os resultados.
Veja este código executado ao vivo em IdeOne.com .
CAVEAT Cuidado com o risco de backup em fluxo
Iterable
. Explicado no correto resposta de Holger .fonte
Stream<String>
porquestream::iterator
não é do tipoStream<String>
.Iterable
através de uma referência de método; o(Iterable<String>)
just diz ao compilador qual interface funcional é o destino.(Iterable<String>)
nada além de um elenco, mas certamente não entendo a situação, pois seus comentários me levaram a colocar um conjunto extra de parênteses em torno do( (Iterable<String>) stream )
qual causa falha no código - provando que meu entendimento é falho. Portanto, edite minha resposta para esclarecer ou publique sua própria resposta com uma explicação melhor.(Iterable<String>)()->stream.iterator()
ou ainda mais explicitamentenew Iterable<String>(){ public Iterator<String> iterator(){ return stream.iterator();}
. Portanto, você não está transmitindo um fluxo para o Iterable, o que falharia.