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 queStream
es algo que solo se puede usar una vez, más como unIterator
.Si el
Iterable
extendido deStream
código existente puede sorprenderse cuando recibe unIterable
que lanza unaException
la segunda vez que lo hacenfor (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.