Konwersja Iterable do Stream przy użyciu Java 8 JDK

Mam interfejs, który zwraca java.lang.Iterable<T>.

Chciałbym manipulować tym wynikiem za pomocą Java 8 Stream API.

Iterable nie może jednak "streamować".

Jakiś pomysł, jak użyć Iterable jako strumienia bez konwersji go do listy?

Author: Matthias Braun, 2014-05-29

9 answers

Jest o wiele lepsza odpowiedź niż użycie spliteratorUnknownSize bezpośrednio, co jest zarówno łatwiejsze, jak i daje lepszy wynik. Iterable ma metodę spliterator(), więc powinieneś jej użyć, aby uzyskać swój spliterator. W najgorszym przypadku jest to ten sam kod (Domyślna implementacja używa spliteratorUnknownSize), ale w bardziej powszechnym przypadku, gdy twoja Iterable jest już kolekcją, otrzymasz lepszy spliterator, a tym samym lepszą wydajność strumienia (może nawet dobrą równoległość). Jest też mniej kodu:

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

As you can zobacz, uzyskanie strumienia z Iterable (patrz również to pytanie ) nie jest zbyt bolesne.

 605
Author: Brian Goetz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-04 16:23:26

Jeśli możesz używać biblioteki Guava, od wersji 21, możesz użyć

Streams.stream(iterable)
 83
Author: numéro6,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-16 09:11:18

Możesz łatwo utworzyć Stream z Iterable lub Iterator:

public static <T> Stream<T> stream(Iterable<T> iterable) {
    return StreamSupport.stream(
        Spliterators.spliteratorUnknownSize(
            iterable.iterator(),
            Spliterator.ORDERED
        ),
        false
    );
}
 24
Author: nosid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-08 13:53:59

Chciałbym zasugerować Użycie biblioteki JOOL , która ukrywa magię spliteratora za wywołaniem Seq.seq(iterable), a także zapewnia całą masę dodatkowych przydatnych funkcjonalności.

 8
Author: Shaggie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-11 19:39:27

Tak jak inna odpowiedź wspomniana Guava ma wsparcie dla tego za pomocą:

Streams.stream(iterable);

Chcę podkreślić, że implementacja robi coś nieco innego niż inne sugerowane odpowiedzi. Jeśli {[2] } jest typu Collection, rzucają go.

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
  );
}
 6
Author: Alexander Oh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-03 12:09:53

I ' ve created this class:

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

Myślę, że jest doskonale czytelny, ponieważ nie musisz myśleć o spliteratorach i booleanach (isParallel).

 5
Author: g-t,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-21 10:31:49

Bardzo prostym obejściem tego problemu jest utworzenie Streamable<T> interfejsu rozszerzającego Iterable<T>, który zawiera metodę default <T> stream().

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

Teraz każdy z twoich Iterable<T>s może być trywialnie streamowalny tylko przez zadeklarowanie ich implements Streamable<T> zamiast Iterable<T>.

 4
Author: OldCurmudgeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-09 10:27:45

Jeśli zdarzy ci się użyć Vavr (wcześniej znanego jako Javaslang), może to być tak proste, jak:

Iterable i = //...
Stream.ofAll(i);
 0
Author: Grzegorz Piwowarek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-25 17:30:53

Inny sposób, aby to zrobić, z Java 8 i bez zewnętrznych bibliotek:

Stream.concat(collectionA.stream(), collectionB.stream())
      .collect(Collectors.toList())
 -2
Author: Greg Witczak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-10 10:44:40