¿Cómo convertir un iterador en una secuencia?
Estoy buscando una forma concisa de convertir an Iterator
en a Stream
o, más específicamente, "ver" el iterador como una secuencia.
Por motivos 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();
Según algunas sugerencias de los comentarios, también intenté utilizar 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
(dado 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)
He mirado StreamSupport
y Collections
pero no encontré nada.
Una forma es crear un archivo Spliterator
a partir de Iterator
y usarlo como base para tu transmisión:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Stream<String> targetStream = StreamSupport.stream(
Spliterators.spliteratorUnknownSize(sourceIterator, Spliterator.ORDERED),
false);
Una alternativa que quizás sea más legible es usar un Iterable
- y crear un Iterable
a partir de un Iterator
es muy fácil con lambdas porque Iterable
es una interfaz funcional:
Iterator<String> sourceIterator = Arrays.asList("A", "B", "C").iterator();
Iterable<String> iterable = () -> sourceIterator;
Stream<String> targetStream = StreamSupport.stream(iterable.spliterator(), false);
Desde la versión 21, la biblioteca Guava proporcionaStreams.stream(iterator)
Hace lo que muestra la respuesta de @ assylias .
¡Gran sugerencia! Aquí está mi versión reutilizable:
public class StreamUtils {
public static <T> Stream<T> asStream(Iterator<T> sourceIterator) {
return asStream(sourceIterator, false);
}
public static <T> Stream<T> asStream(Iterator<T> sourceIterator, boolean parallel) {
Iterable<T> iterable = () -> sourceIterator;
return StreamSupport.stream(iterable.spliterator(), parallel);
}
}
Y uso (asegúrese de importar estáticamente asStream):
List<String> aPrefixedStrings = asStream(sourceIterator)
.filter(t -> t.startsWith("A"))
.collect(toList());
Esto es posible en Java 9.
Stream.generate(() -> null)
.takeWhile(x -> iterator.hasNext())
.map(n -> iterator.next())
.forEach(System.out::println);