Converti Iterable in Stream usando Java 8 JDK

Ho un’interfaccia che restituisce java.lang.Iterable .

Mi piacerebbe manipolare quel risultato usando l’API Java 8 Stream.

Tuttavia Iterable non può “Stream”.

Qualche idea migliore su come utilizzare gli stream (senza convertire Iterable in List)?

C’è una risposta molto migliore rispetto all’uso di spliteratorUnknownSize direttamente, che è sia più facile che ottiene un risultato migliore. Iterable ha un metodo spliterator() , quindi dovresti semplicemente usarlo per ottenere il tuo spliterator. Nel peggiore dei casi, è lo stesso codice (l’implementazione predefinita utilizza spliteratorUnknownSize ), ma nel caso più comune, dove il tuo Iterable è già una raccolta, otterrai uno splitteratore migliore e quindi prestazioni di streaming migliori (forse anche un buon parallelismo .) È anche meno codice:

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

Come puoi vedere, ottenere un stream da un Iterable (vedi Perché Iterable non fornisce i metodi stream () e parallelStream ()? ) Non è molto doloroso.

Se è ansible utilizzare la libreria Guava, dalla versione 21, è ansible utilizzare

 Streams.stream(iterable) 

Puoi creare facilmente un Stream da Iterable o Iterator :

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

Vorrei suggerire di usare la libreria JOOL , nasconde la magia dello splitterator dietro la chiamata Seq.seq (iterable) e fornisce anche un sacco di funzionalità utili aggiuntive.

Ho creato questa class:

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

Penso che sia perfettamente leggibile perché non devi pensare agli spliterator e ai booleans (isParallel).

Una soluzione molto semplice per risolvere questo problema è creare Streamable Iterable estendibile Iterable che contiene un metodo default stream() .

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

Ora uno qualsiasi dei tuoi Iterable può essere reso banale in streaming solo dichiarandoli implements Streamable posto di Iterable .

Quindi, come un’altra risposta citato Guava ha il supporto per questo utilizzando:

 Streams.stream(iterable); 

Voglio sottolineare che l’implementazione fa qualcosa di leggermente diverso rispetto ad altre risposte suggerite. Se l’ Iterable è di tipo Collection lo lanciano.

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

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

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