webentwicklung-frage-antwort-db.com.de

Konvertieren Sie Iterable in Stream mit Java 8 JDK

Ich habe eine Schnittstelle, die Java.lang.Iterable<T> zurückgibt.

Ich möchte dieses Ergebnis mit der Stream-API von Java 8 bearbeiten.

Iterable kann jedoch nicht "streamen".

Haben Sie eine Idee, wie Sie den Iterable als Stream verwenden können, ohne ihn in List zu konvertieren?

389
rayman

Es gibt eine viel bessere Antwort als die direkte Verwendung von spliteratorUnknownSize, was sowohl einfacher ist als auch zu einem besseren Ergebnis führt. Iterable hat eine spliterator() -Methode, daher sollten Sie diese nur verwenden, um Ihren Spliterator zu erhalten. Im schlimmsten Fall ist es derselbe Code (in der Standardimplementierung wird spliteratorUnknownSize verwendet), aber im allgemeineren Fall, in dem Iterable bereits eine Sammlung ist, erhalten Sie einen besseren Spliterator bessere Stream-Leistung (vielleicht sogar gute Parallelität). Es ist auch weniger Code:

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

Wie Sie sehen können, ist es nicht sehr schmerzhaft, einen Stream von einem Iterable zu erhalten (siehe auch diese Frage ).

525
Brian Goetz

Wenn Sie die Guava-Bibliothek verwenden können, können Sie sie seit Version 21 verwenden

Streams.stream(iterable)
59
numéro6

Sie können ganz einfach Stream aus Iterable oder Iterator erstellen:

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

Ich möchte vorschlagen, die Bibliothek JOOL zu verwenden, die Spliterator-Magie hinter dem Aufruf Seq.seq (iterable) verbirgt und eine ganze Reihe zusätzlicher nützlicher Funktionen bereitstellt.

9
Shaggie

Wie eine andere Antwort bereits sagte, unterstützt Guava dies durch die Verwendung von:

Streams.stream(iterable);

Ich möchte hervorheben, dass die Implementierung etwas anderes tut als andere vorgeschlagene Antworten. Wenn das Iterable vom Typ Collection ist, wird es gewirkt.

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
  );
}
4
Alex

Ich habe diese Klasse erstellt:

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);
    }
}

Ich denke, es ist perfekt lesbar, weil Sie nicht über Spliteratoren und Boolesche Werte (isParallel) nachdenken müssen.

3
g-t

Eine sehr einfache Abhilfe für dieses Problem besteht darin, eine Streamable<T> -Schnittstelle zu erstellen, die Iterable<T> erweitert und eine default <T> stream() -Methode enthält.

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

Jetzt kann jeder Ihrer Iterable<T>s einfach zum Streaming gebracht werden, indem sie implements Streamable<T> anstelle von Iterable<T> deklariert werden.

3
OldCurmudgeon

Wenn Sie zufällig Vavr (früher als Javaslang bekannt) verwenden, kann dies so einfach sein wie:

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