¿Cómo convertir un iterador a una secuencia?

Estoy buscando una forma concisa para convertir un Iterator en un Stream o más específicamente para “ver” el iterador como una secuencia.

Por razones de rendimiento, me gustaría evitar una copia del iterador en una nueva lista:

 Iterator sourceIterator = Arrays.asList("A", "B", "C").iterator(); Collection copyList = new ArrayList(); sourceIterator.forEachRemaining(copyList::add); Stream targetStream = copyList.stream(); 

En base a algunas sugerencias en los comentarios, también intenté usar Stream.generate :

 public static void main(String[] args) throws Exception { Iterator sourceIterator = Arrays.asList("A", "B", "C").iterator(); Stream targetStream = Stream.generate(sourceIterator::next); targetStream.forEach(System.out::println); } 

Sin embargo, obtengo una NoSuchElementException (ya que no hay una 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 consultado StreamSupport y Collections pero no encontré nada.

Una forma es crear un Spliterator del iterador y usarlo como base para su transmisión:

 Iterator sourceIterator = Arrays.asList("A", "B", "C").iterator(); Stream 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 desde un Iterator es muy fácil con lambdas porque Iterable es una interfaz funcional:

 Iterator sourceIterator = Arrays.asList("A", "B", "C").iterator(); Iterable iterable = () -> sourceIterator; Stream targetStream = StreamSupport.stream(iterable.spliterator(), false); 

¡Gran sugerencia! Aquí está mi opinión reutilizable:

 public class StreamUtils { public static  Stream asStream(Iterator sourceIterator) { return asStream(sourceIterator, false); } public static  Stream asStream(Iterator sourceIterator, boolean parallel) { Iterable iterable = () -> sourceIterator; return StreamSupport.stream(iterable.spliterator(), parallel); } } 

Y uso (asegúrese de importar estáticamente AsStream):

 List aPrefixedStrings = asStream(sourceIterator) .filter(t -> t.startsWith("A")) .collect(toList()); 

Desde la versión 21, la biblioteca de Guava proporciona Streams.stream(iterator)

Hace lo que la respuesta de @ assylias muestra.

Esto es posible en Java 9 que no usa nada más que transmisiones, sin embargo, hay una advertencia que hay que tener en cuenta. El siguiente ejemplo ingenuo no imprimirá el último elemento del iterador.

 Stream.generate(iterator::next) .takeWhile(i -> iterator.hasNext()) .forEach(System.out::println); 

Esto, sin embargo, funciona correctamente:

 Stream.generate(() -> null) .takeWhile(x -> iterator.hasNext()) .map(n -> iterator.next()) .forEach(System.out::println); 

Crear Spliterator from Spliterator usando la clase Spliterators contiene más de una función para crear spliterator, por ejemplo aquí estoy usando spliteratorUnknownSize que está obteniendo el iterador como parámetro, luego creo Stream usando StreamSupport

 Spliterator spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL); Stream stream = StreamSupport.stream(spliterator, false); 

Use Collections.list(iterator).stream()...