Converti Iterable in Stream utilizzando Java 8 JDK


420

Ho un'interfaccia che ritorna java.lang.Iterable<T>.

Vorrei manipolare quel risultato usando l'API Java 8 Stream.

Tuttavia Iterable non può "trasmettere".

Qualche idea su come usare l'Iterable come Stream senza convertirlo in Elenco?


2
Se riesci a iterare, perché non usare semplicemente un ciclo per verificarne le condizioni o il valore o che altro?
Afzaal Ahmad Zeeshan,

26
@AfzaalAhmadZeeshan perché i flussi sono molto meglio
Sleiman Jneidi

1
Come ho detto, ho bisogno di fare alcune maniuplations su quell'elenco (filtri, mappatura). Vorrei utilizzare la nuova API JDK Java 8 -> Stream. ma Iterable non è "SteamAble"
rayman

Sembra strano che myIterable.stream()non esista!
Josh M.,

7
@Guillaume: Sì, ma Stream.of(iterable)produce Stream<Iterable<Object>>.
Matthias Braun,

Risposte:


573

C'è una risposta molto migliore rispetto all'utilizzo spliteratorUnknownSizediretto, che è sia più semplice che ottiene un risultato migliore. Iterableha un spliterator()metodo, quindi dovresti semplicemente usarlo per ottenere il tuo divisore. Nel peggiore dei casi, è lo stesso codice (utilizzato dall'implementazione predefinita spliteratorUnknownSize), ma nel caso più comune, dove la tua Iterableè già una raccolta, otterrai uno splitterator migliore e quindi migliori prestazioni dello stream (forse anche un buon parallelismo). È anche meno codice:

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

Come puoi vedere, ottenere un flusso da un Iterable(vedi anche questa domanda ) non è molto doloroso.


109
Un metodo statico su Streamsarebbe stato carino, ad es Stream.ofIterable(iterable).
Robininst

59
@robinst Questa non era un'omissione; è stata una scelta deliberata (e molto dibattuta). La sfida è che se ciò esistesse, sarebbe troppo facile raggiungerlo senza capire i compromessi che ne derivano. Poiché Iterable è così astratto, un tale metodo comporterebbe il flusso con le prestazioni peggiori possibili (nessun supporto parallelo, nessuna informazione sulle dimensioni o caratteristiche (usato per ottimizzare le scelte di esecuzione)). Forzare più risultati di pensiero in API migliori nell'intero ecosistema. Questo è stato un compromesso tra "ciò che è meglio per il codice XYZ" vs "ciò che è meglio per tutto il codice Java".
Brian Goetz,

2
Sulla base della tua spiegazione, sono curioso di sapere perché abbiamo Collection.stream () ma non Iterable.stream (). Sembra che il ragionamento per omettere Iterable.stream () (o Stream.ofIterable ()) si applichi ugualmente a Collection.stream ().
Qualidafial


11
@BrianGoetz Sembra che la maggior parte delle persone non siano nel livello per capire che hai detto sopra o non ti interessa. vogliono solo scrivere il codice semplice chiamando l'API semplice. D'altra parte, quelle cose (parallele ...) potrebbero non essere importanti per la maggior parte delle operazioni ripetibili quotidiane.
user_3380739


23

Puoi facilmente creare un Streamda Iterableo Iterator:

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

2
Devi scrivere questa funzione una volta e poi chiamarla. Perché una chiamata per stream(...)ingombrare il tuo codice?
gexicide,

1
Volevo farlo Inline breve ed elegante .. hai ragione, posso scrivere questa funzione una volta .. ma mi piace rilasciare il codice (e non aggiungere codice). comunque questa risposta è giusta perché è il modo di convertirla.
Rayman,

importazione statica detta funzione. corto ed elegante. (anche se non necessariamente trasparente)
aepurniet,

9

Vorrei suggerire di utilizzare la libreria JOOL , nasconde la magia spliterator dietro la chiamata Seq.seq (iterabile) e fornisce anche un sacco di funzionalità utili aggiuntive.


7

Quindi, come menzionato in un'altra risposta, Guava ha il supporto per questo usando:

Streams.stream(iterable);

Voglio sottolineare che l'implementazione fa qualcosa di leggermente diverso rispetto alle altre risposte suggerite. Se Iterableè di tipo, Collectionlo lanciano.

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

Ho creato questa classe:

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

Penso che sia perfettamente leggibile perché non devi pensare a divisori e booleani (isParallel).


4

Una soluzione molto semplice per questo problema consiste nel creare Streamable<T>un'interfaccia estesa Iterable<T>che contenga un default <T> stream()metodo.

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

Ora qualcuno dei tuoi Iterable<T> è possibile rendere banalmente streaming messaggi semplicemente dichiarandoli implements Streamable<T>anziché Iterable<T>.


0

Se ti capita di usare Vavr (precedentemente noto come Javaslang), questo può essere facile come:

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

-1

Un altro modo per farlo, con Java 8 e senza librerie esterne:

Stream.concat(collectionA.stream(), collectionB.stream())
      .collect(Collectors.toList())
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.