2016-03-16 9 views
22

In Java, è possibile generare facilmente un flusso infinito con Stream.generate(supplier). Tuttavia, avrei bisogno di generare un flusso che alla fine finirà.Flusso generato finito in Java - come crearne uno?

Immaginate, per esempio, voglio un flusso di tutti i file in una directory. Il numero di file può essere enorme, quindi non posso raccogliere tutti i dati in anticipo e creare un flusso da loro (tramite collection.stream()). Ho bisogno di generare la sequenza pezzo per pezzo. Ma lo stream ovviamente finirà ad un certo punto, e gli operatori terminal come (collect() o findAny()) devono lavorarci sopra, quindi Stream.generate(supplier) non è adatto qui.

Esiste un modo ragionevole ragionevole per farlo in Java, senza implementare l'intera interfaccia Stream da solo?

Mi viene in mente un semplice trucco: eseguirlo con infinito Stream.generate(supplier) e fornire null o generare un'eccezione quando vengono presi tutti i valori effettivi. Ma romperebbe gli operatori standard di streaming, potrei usarlo solo con i miei operatori che sono a conoscenza di questo comportamento.

CHIARIMENTO

persone nei commenti mi propongono takeWhile() operatore. Questo non è quello che intendevo. Come esprimere meglio la domanda ... Non sto chiedendo come filtrare (o limitare) uno stream esistente, sto chiedendo come creare (generare) lo stream - in modo dinamico, senza caricare tutti gli elementi in anticipo, ma lo stream avrebbe una dimensione finita (sconosciuta in anticipo).

SOLUZIONE

Il codice che cercavo è

Iterator it = myCustomIteratorThatGeneratesTheSequence(); 
    StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false); 

Ho appena guardato in java.nio.file.Files, come il metodo list(path) è implementato.

+0

Non credo di capire. Stai cercando una sorta di 'takeWhile' come qui http://stackoverflow.com/q/20746429/1743880? – Tunaki

+1

Hai dato un'occhiata a metodi come [IntStream.range] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/IntStream.html#range-int-int-) e amici? –

+0

'openjdk 9' fornisce' takeWhile() ' – Andrew

risposta

7

Esiste un modo ragionevole ragionevole per farlo in Java, senza implementare l'intera interfaccia Stream da solo?

Un semplice .limit() garantisce che terminerà. Ma non è sempre abbastanza potente.

Dopo le Stream metodi di fabbrica l'approccio più semplice per la creazione di fonti di flusso doganali, senza reimplementare pipeline di elaborazione flusso è Subclassing java.util.Spliterators.AbstractSpliterator<T> e passarlo a java.util.stream.StreamSupport.stream(Supplier<? extends Spliterator<T>>, int, boolean)

Se avete intenzione di utilizzare flussi paralleli di notare che AbstractSpliterator cede solo non ottimale splitting. Se si dispone di un maggiore controllo sulla fonte, è possibile migliorare l'implementazione dell'interfaccia Spliterator.

Ad esempio, il seguente snippet creerebbe un flusso che fornisce una sequenza infinita 1,2,3 ...

in quel particolare esempio si potrebbe utilizzare IntStream.range()

Ma il flusso sarà, ovviamente, finire a un certo punto, e gli operatori dei terminali, come (raccogliere() o findAny()) bisogno di lavorare su di esso.

operazioni di cortocircuito come findAny() possono effettivamente terminare su un flusso infinito, purché vi sia un elemento corrispondente.