Convertir Iterable a Stream usando Java 8 JDK


420

Tengo una interfaz que vuelve java.lang.Iterable<T>.

Me gustaría manipular ese resultado utilizando la API Java 8 Stream.

Sin embargo, Iterable no puede "transmitir".

¿Alguna idea de cómo usar Iterable como Stream sin convertirlo en List?


2
Si puede iterar, ¿por qué no usar simplemente un bucle para verificar su condición o valor o lo que sea?
Afzaal Ahmad Zeeshan

26
@AfzaalAhmadZeeshan porque las transmisiones son mucho mejores
Sleiman Jneidi

1
Como dije, necesito hacer algunas manipulaciones en esa lista (filtros, mapeo). Me gustaría utilizar la nueva API Java 8 JDK -> Stream. pero Iterable no es "SteamAble"
rayman

Parece extraño que myIterable.stream()no existe!
Josh M.

77
@ Guillaume: Sí, pero Stream.of(iterable)produce Stream<Iterable<Object>>.
Matthias Braun

Respuestas:


573

Hay una respuesta mucho mejor que usar spliteratorUnknownSizedirectamente, lo cual es más fácil y obtiene un mejor resultado. Iterabletiene un spliterator()método, por lo que debe usarlo para obtener su spliterator. En el peor de los casos, es el mismo código (la implementación predeterminada lo usa spliteratorUnknownSize), pero en el caso más común, donde Iterableya es una colección, obtendrá un mejor spliterator y, por lo tanto, un mejor rendimiento de transmisión (tal vez incluso un buen paralelismo). También es menos código:

StreamSupport.stream(iterable.spliterator(), false)
             .filter(...)
             .moreStreamOps(...);

Como puede ver, obtener una transmisión de un Iterable(vea también esta pregunta ) no es muy doloroso.


109
Un método estático en Streamhabría sido bueno, por ejemplo Stream.ofIterable(iterable).
robinst

59
@robinst Esto no fue una omisión; fue una elección deliberada (y muy debatida). El desafío es que si esto existiera, sería demasiado fácil alcanzarlo sin comprender las compensaciones que conlleva. Debido a que Iterable es tan abstracto, dicho método daría como resultado el flujo de peor rendimiento posible (sin soporte paralelo, sin información de tamaño o características (utilizado para optimizar las opciones de ejecución)). Forzar más resultados de pensamiento en mejores API en todo el ecosistema. Esto fue una compensación de "lo mejor para el código XYZ" frente a "lo mejor para todo el código Java".
Brian Goetz el

2
Según su explicación, tengo curiosidad por saber por qué obtuvimos Collection.stream () pero no Iterable.stream (). Parece que el razonamiento para omitir Iterable.stream () (o Stream.ofIterable ()) se aplica igualmente a Collection.stream ().
qualidafial


11
@BrianGoetz Parece que la mayoría de las personas no están en el nivel para entender lo que dijo anteriormente o no les importa. solo quieren escribir el código simple llamando a API simple. Por otro lado, esas cosas (paralelas ...) tal vez no sean importantes para la mayoría de las operaciones iterables diarias.
user_3380739


23

Puede crear fácilmente Streamun Iterableo Iterator:

public static <T> Stream<T> stream(Iterable<T> iterable) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            iterable.iterator(),
            Spliterator.ORDERED
        ),
        false
    );
}

2
Tienes que escribir esta función una vez y luego simplemente llamarla. ¿Por qué una llamada para stream(...)saturar tu código?
Gexicida

1
Quería hacerlo en línea, corto y elegante ... tienes razón, puedo escribir esta función una vez ... pero me gusta soltar código (y no agregar código). de todos modos esta respuesta es correcta porque esa es la forma de convertir esto.
rayman

importación estática dicha función. Corto y elegante. (aunque no necesariamente transparente)
aepurniet

9

Me gustaría sugerir el uso de la biblioteca JOOL , oculta la magia de spliterator detrás de la llamada Seq.seq (iterable) y también proporciona un montón de funcionalidades adicionales útiles.


7

Entonces, como otra respuesta mencionó, Guava tiene soporte para esto al usar:

Streams.stream(iterable);

Quiero resaltar que la implementación hace algo ligeramente diferente a otras respuestas sugeridas. Si el Iterablees de tipo, Collectionlo echan.

public static <T> Stream<T> stream(Iterable<T> iterable) {
  return (iterable instanceof Collection)
    ? ((Collection<T>) iterable).stream()
    : StreamSupport.stream(iterable.spliterator(), false);
}

public static <T> Stream<T> stream(Iterator<T> iterator) {
  return StreamSupport.stream(
    Spliterators.spliteratorUnknownSize(iterator, 0),
    false
  );
}

5

He creado esta clase:

public class Streams {
    /**
     * Converts Iterable to stream
     */
    public static <T> Stream<T>  streamOf(final Iterable<T> iterable) {
        return toStream(iterable, false);
    }

    /**
     * Converts Iterable to parallel stream
     */
    public static <T> Stream<T> parallelStreamOf(final Iterable<T> iterable) {
        return toStream(iterable, true);
    }

    private static <T> Stream<T> toStream(final Iterable<T> 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).


4

Una solución muy simple para este problema es crear una Streamable<T>interfaz Iterable<T>que se extienda y que contenga un default <T> stream()método.

interface Streamable<T> extends Iterable<T> {
    default Stream<T> stream() {
        return StreamSupport.stream(spliterator(), false);
    }
}

Ahora cualquiera de tus Iterable<T>correos electrónicos se puede hacer trivialmente en streaming simplemente declarándolos en implements Streamable<T>lugar de hacerlo Iterable<T>.


0

Si utiliza Vavr (anteriormente conocido como Javaslang), esto puede ser tan fácil como:

Iterable i = //...
Stream.ofAll(i);

-1

Otra forma de hacerlo, con Java 8 y sin bibliotecas externas:

Stream.concat(collectionA.stream(), collectionB.stream())
      .collect(Collectors.toList())
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.