example java java-8 java-stream iterable

java - example - iterable python



¿Por qué Stream<T> no implementa Iterable<T>? (9)

Me gustaría señalar que StreamEx implementa Iterable (y Stream ), así como una gran cantidad de otras funciones increíblemente impresionantes que faltan en Stream .

En Java 8 tenemos la clase Stream<T> , que curiosamente tiene un método.

Iterator<T> iterator()

Por lo tanto, es de esperar que implemente la interfaz Iterable<T> , que requiere exactamente este método, pero ese no es el caso.

Cuando quiero recorrer una secuencia usando un bucle foreach, tengo que hacer algo como

public static Iterable<T> getIterable(Stream<T> s) { return new Iterable<T> { @Override public Iterator<T> iterator() { return s.iterator(); } }; } for (T element : getIterable(s)) { ... }

¿Me estoy perdiendo de algo?


No es perfecto, pero funcionará:

iterable = stream.collect(Collectors.toList());

No es perfecto porque recogerá todos los elementos de la secuencia y los pondrá en esa List , que no es exactamente de lo que se trata Iterable y Stream . Se supone que son lazy .


Para convertir un Stream a un Iterable , puedes hacer

Stream<X> stream = null; Iterable<X> iterable = stream::iterator

Para pasar un Stream a un método que espera Iterable ,

void foo(Iterable<X> iterable)

simplemente

foo(stream::iterator)

Sin embargo, probablemente se ve divertido; Podría ser mejor ser un poco más explícito

foo( (Iterable<X>)stream::iterator );


Puede iterar sobre todos los archivos en una carpeta usando Stream<Path> siguiente manera:

Path path = Paths.get("..."); Stream<Path> files = Files.list(path); for (Iterator<Path> it = files.iterator(); it.hasNext(); ) { Object file = it.next(); // ... }


Puedes usar un Stream en un bucle for siguiente manera:

Stream<T> stream = ...; for (T x : (Iterable<T>) stream::iterator) { ... }

(Ejecutar este fragmento aquí )

(Esto utiliza una interfaz funcional de Java 8).

(Esto se trata en algunos de los comentarios anteriores (por ejemplo, Aleksandr Dubinsky ), pero quería explicarlo para que sea más visible).


Si no le importa usar bibliotecas de terceros, cyclops-react define un Stream que implementa tanto Stream como Iterable y también es reproducible (solucionando el problema descrito por kennytm ).

Stream<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s);

o: -

Iterable<String> stream = ReactiveSeq.of("hello","world") .map(s->"prefix-"+s); stream.forEach(System.out::println); stream.forEach(System.out::println);

[Revelación Soy el desarrollador líder de cyclops-react]


Ya hay personas preguntadas lo mismo en la lista de correo . La razón principal es que Iterable también tiene una semántica repetible, mientras que Stream no lo es.

Creo que la razón principal es que Iterable implica reutilización, mientras que Stream es algo que solo se puede usar una vez, más como un Iterator .

Si el Iterable extendido de Stream código existente puede sorprenderse cuando recibe un Iterable que lanza una Exception la segunda vez que lo hacen for (element : iterable) .


Stream no implementa Iterable . La comprensión general de Iterable es cualquier cosa que pueda repetirse, a menudo una y otra vez. Stream no puede ser reproducible.

La única solución que se me ocurre, donde también se puede reproducir una iterable basada en una transmisión, es volver a crear la transmisión. Estoy utilizando un Supplier continuación para crear una nueva instancia de flujo, cada vez que se crea un nuevo iterador.

Supplier<Stream<Integer>> streamSupplier = () -> Stream.of(10); Iterable<Integer> iterable = () -> streamSupplier.get().iterator(); for(int i : iterable) { System.out.println(i); } // Can iterate again for(int i : iterable) { System.out.println(i); }


kennytm describió por qué no es seguro tratar un Stream como un Iterable , y Zhong Yu ofreció una solución que permite usar un Stream como Iterable , aunque de una manera insegura. Es posible obtener lo mejor de ambos mundos: un Iterable reutilizable de un Stream que cumple con todas las garantías Iterable por la especificación Iterable .

Nota: SomeType no es un parámetro de tipo aquí; debe reemplazarlo con un tipo adecuado (por ejemplo, String ) o recurrir a la reflexión

Stream<SomeType> stream = ...; Iterable<SomeType> iterable = stream.collect(toList()):

Hay una desventaja importante:

Los beneficios de la iteración perezosa se perderán. Si planeaba iterar inmediatamente sobre todos los valores en el subproceso actual, cualquier sobrecarga será despreciable. Sin embargo, si planeaba iterar solo parcialmente o en un hilo diferente, esta iteración inmediata y completa podría tener consecuencias no deseadas.

La gran ventaja, por supuesto, es que puede reutilizar Iterable , mientras que (Iterable<SomeType>) stream::iterator solo permitiría un uso único. Si el código de recepción iterará sobre la colección varias veces, esto no solo es necesario, sino que también es beneficioso para el rendimiento.