Busco una manera concisa para convertir una Iterator
a una Stream
o más específicamente a "ver" el iterador como una corriente.
Por razones de rendimiento, me gustaría evitar una copia del iterador en una nueva lista:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Collection<String> copyList = new ArrayList<String>();
sourceIterator.forEachRemaining(copyList::add);
Stream<String> targetStream = copyList.stream();
Basado en algunas sugerencias en los comentarios, también he tratado de usar Stream.generate
:
public static void main(String[] args) throws Exception {
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = Stream.generate(sourceIterator::next);
targetStream.forEach(System.out::println);
}
Sin embargo, obtengo un NoSuchElementException
(ya que no hay invocación de hasNext
)
Exception in thread "main" java.util.NoSuchElementException
at java.util.AbstractList$Itr.next(AbstractList.java:364)
at Main$$Lambda$1/1175962212.get(Unknown Source)
at java.util.stream.StreamSpliterators$InfiniteSupplyingSpliterator$OfRef.tryAdvance(StreamSpliterators.java:1351)
at java.util.Spliterator.forEachRemaining(Spliterator.java:326)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
at Main.main(Main.java:20)
Lo miré StreamSupport
y Collections
no encontré nada.
Stream.generate(iterator::next)
funciona?Respuestas:
Una forma es crear un Spliterator desde el Iterator y usarlo como base para su transmisión:
Una alternativa que tal vez sea más legible es usar un Iterable, y crear un Iterable desde un Iterator es muy fácil con lambdas porque Iterable es una interfaz funcional:
fuente
sourceIterator.next()
antes de usar la transmisión y verá el efecto (la transmisión no verá el primer elemento).Iterable<String> iterable = () -> sourceIterator;
. Tengo que admitir que me tomó un tiempo entenderlo.Iterable<T>
es unFunctionalInterface
que solo tiene un método abstractoiterator()
. Entonces, ¿() -> sourceIterator
es una expresión lambda instanciando unaIterable
instancia como una implementación anónima?() -> sourceIterator;
es una forma abreviada denew Iterable<>() { @Override public Iterator<String> iterator() { return sourceIterator; } }
Desde la versión 21, la biblioteca Guava proporciona
Streams.stream(iterator)
Se hace lo @ assylias 's respuesta espectáculos .
fuente
Gran sugerencia! Aquí está mi versión reutilizable:
Y uso (asegúrese de importar estáticamente asStream):
fuente
Esto es posible en Java 9.
fuente
.parallel()
transmisiones. También parecen un poco más lentos que irSpliterator
, incluso para uso secuencial.parallel
podría ser funky, la sencillez es increíble.La clase Create
Spliterator
fromIterator
usingSpliterators
contiene más de una función para crear spliterator, por ejemplo, aquí estoy usandospliteratorUnknownSize
el iterador como parámetro, luego cree Stream usandoStreamSupport
fuente
y uso
Streams.stream(iterator)
:fuente
Otra forma de hacer esto en Java 9+ usando Stream :: iterate (T, Predicate, UnaryOperator) :
fuente
Utilizar
Collections.list(iterator).stream()...
fuente