I flussi Java 8 sono simili agli osservabili RxJava?
Definizione stream Java 8:
Le classi nel nuovo
java.util.stream
pacchetto forniscono un'API Stream per supportare operazioni in stile funzionale su flussi di elementi.
I flussi Java 8 sono simili agli osservabili RxJava?
Definizione stream Java 8:
Le classi nel nuovo
java.util.stream
pacchetto forniscono un'API Stream per supportare operazioni in stile funzionale su flussi di elementi.
Risposte:
TL; DR : tutte le librerie di elaborazione sequenza / flusso offrono API molto simili per la creazione di pipeline. Le differenze sono nelle API per la gestione del multi-threading e della composizione delle condutture.
RxJava è abbastanza diverso da Stream. Di tutte le cose JDK, il più vicino a rx.Observable è forse java.util.stream.Collector Stream + CompletableFuture combo (che ha un costo per gestire un livello extra di monade, cioè dover gestire la conversione tra Stream<CompletableFuture<T>>
e CompletableFuture<Stream<T>>
).
Esistono differenze significative tra Observable e Stream:
Stream#parallel()
divide la sequenza in partizioni Observable#subscribeOn()
e Observable#observeOn()
non; è difficile emulare il Stream#parallel()
comportamento con Observable, una volta aveva il .parallel()
metodo ma questo metodo causava tanta confusione che il .parallel()
supporto è stato spostato in un repository separato su github, RxJavaParallel. Maggiori dettagli sono in un'altra risposta .Stream#parallel()
non consente di specificare un pool di thread da utilizzare, a differenza della maggior parte dei metodi RxJava che accettano l'Utilità di pianificazione opzionale. Poiché tutte le istanze di streaming in una JVM utilizzano lo stesso pool fork-join, l'aggiunta .parallel()
può influire accidentalmente sul comportamento in un altro modulo del programmaObservable#interval()
, Observable#window()
e molti altri; ciò è principalmente dovuto al fatto che gli stream sono basati su pull e upstream non ha alcun controllo su quando emettere l'elemento successivo a valletakeWhile()
, takeUntil()
); la soluzione alternativa Stream#anyMatch()
è limitata: è un'operazione terminale, quindi non è possibile utilizzarla più di una volta per flussoObservable#using()
); puoi avvolgere IO Stream o Mutex con esso ed essere sicuro che l'utente non dimenticherà di liberare la risorsa: verrà eliminata automaticamente al termine dell'abbonamento; Lo streaming ha un onClose(Runnable)
metodo, ma devi chiamarlo manualmente o tramite prova con risorse. Per esempio. devi tenere presente che File # righe () deve essere racchiuso nel blocco try-with-resources.Riassunto: RxJava differisce significativamente dagli stream. Le alternative reali a RxJava sono altre implementazioni di ReactiveStreams , ad esempio la parte rilevante di Akka.
Aggiornamento . Esistono dei trucchi per utilizzare il pool fork-join non predefinito Stream#parallel
, consultare Pool di thread personalizzati nel flusso parallelo Java 8
Aggiornamento . Tutto quanto sopra si basa sull'esperienza con RxJava 1.x. Ora che RxJava 2.x è qui , questa risposta potrebbe non essere aggiornata.
Stream.generate()
e passare la tua Supplier<U>
implementazione, solo un metodo semplice da cui fornire l'elemento successivo nello stream. Ci sono molti altri metodi. Per costruire facilmente una sequenza Stream
che dipende da valori precedenti puoi usare il interate()
metodo, ognuno Collection
ha un stream()
metodo e Stream.of()
costruisce un Stream
da un varargs o un array. Finalmente StreamSupport
ha il supporto per la creazione di stream più avanzata usando spliterator o per tipi primitivi di stream.
takeWhile()
, takeUntil()
);" - JDK9 ha questi, credo, in takeWhile () e dropWhile ()
Java 8 Stream e RxJava sembrano abbastanza simili. Hanno operatori simili (filtro, mappa, flatMap ...) ma non sono costruiti per lo stesso utilizzo.
È possibile eseguire attività asincrone utilizzando RxJava.
Con Java 8 stream, attraverserai oggetti della tua collezione.
Puoi fare praticamente la stessa cosa in RxJava (attraversare gli elementi di una raccolta) ma, poiché RxJava è focalizzato su attività simultanee, ... usa sincronizzazione, latch, ... Quindi la stessa attività usando RxJava potrebbe essere più lenta di con flusso Java 8.
RxJava può essere paragonato a CompletableFuture
, ma può essere in grado di calcolare più di un solo valore.
parallelStream
supporta una sincronizzazione simile di semplici attraversamenti / mappe / filtri ecc.
Esistono alcune differenze tecniche e concettuali, ad esempio i flussi Java 8 sono sequenze di valori sincrone monouso, basate su pull, mentre le osservabili RxJava sono ri-osservabili, sequenze di valori adattivamente basate su push-pull, potenzialmente asincrone di valori. RxJava è rivolto a Java 6+ e funziona anche su Android.
I flussi Java 8 sono basati su pull. Si scorre su un flusso Java 8 che consuma ogni elemento. E potrebbe essere un flusso infinito.
RXJava Observable
è basato su push predefinito. Ti iscrivi a un osservabile e riceverai una notifica quando arriva l'elemento successivo ( onNext
) o quando lo stream è completato ( onCompleted
) o quando si è verificato un errore ( onError
). Perché con Observable
si riceve onNext
, onCompleted
, onError
eventi, si possono fare alcune funzioni potenti come la combinazione di diversi Observable
s ad una nuova ( zip
, merge
, concat
). Altre cose che potresti fare sono la memorizzazione nella cache, la limitazione, ... E utilizza più o meno la stessa API in diverse lingue (RxJava, RX in C #, RxJS, ...)
Per impostazione predefinita, RxJava è a thread singolo. A meno che non inizi a utilizzare gli Scheduler, tutto accadrà sullo stesso thread.
Le risposte esistenti sono complete e corrette, ma manca un chiaro esempio per i principianti. Consentitemi di inserire alcuni termini concreti come "push / pull-based" e "ri-osservabile". Nota : odio il termine Observable
(è un flusso per l'amor del cielo), quindi farò semplicemente riferimento ai flussi J8 vs RX.
Considera un elenco di numeri interi,
digits = [1,2,3,4,5]
Un flusso J8 è un'utilità per modificare la raccolta. Ad esempio, anche le cifre possono essere estratte come,
evens = digits.stream().filter(x -> x%2).collect(Collectors.toList())
Questa è fondamentalmente la mappa, il filtro, la riduzione di Python , un'aggiunta molto bella (e molto attesa) a Java. E se le cifre non fossero state raccolte in anticipo - e se le cifre fossero state trasmesse in streaming mentre l'app era in esecuzione - potremmo filtrare le cifre pari in tempo reale.
Immagina che un processo di thread separato stia emettendo numeri interi in momenti casuali mentre l'app è in esecuzione ( ---
indica il tempo)
digits = 12345---6------7--8--9-10--------11--12
In RX, even
può reagire ad ogni nuova cifra e applicare il filtro in tempo reale
even = -2-4-----6---------8----10------------12
Non è necessario memorizzare elenchi di input e output. Se si desidera un elenco di output, nessun problema è anche streaming. In effetti, tutto è un flusso.
evens_stored = even.collect()
Questo è il motivo per cui termini come "senza stato" e "funzionale" sono più associati a RX
RxJava è anche strettamente correlato all'iniziativa dei flussi reattivi e si considera una semplice implementazione dell'API dei flussi reattivi (ad esempio rispetto all'implementazione dei flussi Akka ). La differenza principale è che i flussi reattivi sono progettati per essere in grado di gestire la contropressione, ma se dai un'occhiata alla pagina dei flussi reattivi, otterrai l'idea. Descrivono abbastanza bene i loro obiettivi e anche i flussi sono strettamente correlati al manifesto reattivo .
I flussi Java 8 sono praticamente l'implementazione di una collezione illimitata, abbastanza simile al Scala Stream o al pigro seq di Clojure .
Java 8 Streams consente l'elaborazione di raccolte di grandi dimensioni in modo efficiente, sfruttando al contempo le architetture multicore. Al contrario, RxJava è a thread singolo per impostazione predefinita (senza Scheduler). Quindi RxJava non sfrutterà le macchine multi-core a meno che non codifichi tu stesso quella logica.