Tengo una interfaz que devuelve java.lang.Iterable
.
Me gustaría manipular ese resultado utilizando Java 8 Stream API.
Sin embargo, Iterable no puede “transmitir”.
¿Alguna idea mejor de cómo usar las transmisiones (sin convertir Iterable a List)?
Hay una respuesta mucho mejor que usar spliteratorUnknownSize
directamente, que es más fácil y obtiene un mejor resultado. Iterable
tiene un método spliterator()
, por lo que debe usarlo para obtener su spliterator. En el peor de los casos, es el mismo código (la implementación predeterminada usa spliteratorUnknownSize
), pero en el caso más común, donde tu Iterable
ya es una colección, obtendrás un spliterator mejor y, por lo tanto, mejor rendimiento de transmisión (incluso un buen paralelismo) .) También es menos código:
StreamSupport.stream(iterable.spliterator(), false) .filter(...) .moreStreamOps(...);
Como puede ver, obtener un flujo de un Iterable (consulte ¿Por qué Iterable
Si puede usar la biblioteca de guayaba, desde la versión 21, puede usar
Streams.stream(iterable)
Puede crear fácilmente un Stream
de un Iterable
o Iterator
:
public static Stream stream(Iterable iterable) { return StreamSupport.stream( Spliterators.spliteratorUnknownSize( iterable.iterator(), Spliterator.ORDERED ), false ); }
Me gustaría sugerir el uso de la biblioteca JOOL , oculta la magia del spliterator detrás de la llamada Seq.seq (iterable) y también proporciona un montón de funcionalidades útiles adicionales.
Creé esta clase:
public class Streams { /** * Converts Iterable to stream */ public static Stream streamOf(final Iterable iterable) { return toStream(iterable, false); } /** * Converts Iterable to parallel stream */ public static Stream parallelStreamOf(final Iterable iterable) { return toStream(iterable, true); } private static Stream toStream(final Iterable iterable, final boolean isParallel) { return StreamSupport.stream(iterable.spliterator(), isParallel); } }
Creo que es perfectamente legible porque no tienes que pensar en spliterators y booleans (isParallel).
Una Streamable
muy simple para este problema es crear una Streamable
Iterable
que contenga un método default
.
interface Streamable extends Iterable { default Stream stream() { return StreamSupport.stream(spliterator(), false); } }
Ahora cualquiera de tus Iterable
s puede hacerse trivialmente streamable simplemente al declarar que implements Streamable
lugar de Iterable
.
Entonces, como otra respuesta mencionada, Guava tiene soporte para esto al usar:
Streams.stream(iterable);
Quiero resaltar que la implementación hace algo ligeramente diferente de otras respuestas sugeridas. Si el Iterable
es de tipo Collection
lo lanzan.
public static Stream stream(Iterable iterable) { return (iterable instanceof Collection) ? ((Collection ) iterable).stream() : StreamSupport.stream(iterable.spliterator(), false); } public static Stream stream(Iterator iterator) { return StreamSupport.stream( Spliterators.spliteratorUnknownSize(iterator, 0), false ); }
Si usa Vavr (anteriormente conocido como Javaslang), esto puede ser tan fácil como:
Iterable i = //... Stream.ofAll(i);