web-dev-qa-db-ja.com

Java 8ストリームとRxJavaオブザーバブルの違い

Java 8ストリームはRxJavaオブザーバブルに似ていますか?

Java 8ストリーム定義:

新しいJava.util.streamパッケージのクラスは、要素のストリームで機能スタイルの操作をサポートするストリームAPIを提供します。

131
3xplore

TL; DR:すべてのシーケンス/ストリーム処理ライブラリは、パイプライン構築用の非常に類似したAPIを提供しています。違いは、マルチスレッドとパイプラインの構成を処理するためのAPIにあります。

RxJavaはStreamとはまったく異なります。すべてのJDKの中で、rx.Observableに最も近いのはおそらく Java.util.stream.Collector ストリーム+ CompletableFutureコンボ(追加のモナドレイヤーを処理するコストがかかります。つまり、Stream<CompletableFuture<T>>CompletableFuture<Stream<T>>の間の変換を処理する必要があります)。

ObservableとStreamには大きな違いがあります。

  • ストリームはプルベースであり、オブザーバブルはプッシュベースです。これはあまりにも抽象的に聞こえるかもしれませんが、非常に具体的な重要な結果をもたらします。
  • ストリームは1回しか使用できません。Observableは何度もサブスクライブできます
  • Stream#parallel()はシーケンスをパーティションに分割しますが、Observable#subscribeOn()Observable#observeOn()は分割しません。 ObservableでStream#parallel()の動作をエミュレートするのはトリッキーです。かつて.parallel()メソッドがありましたが、このメソッドは非常に混乱を引き起こし、.parallel()サポートがgithubの別のリポジトリRxJavaParallelに移動しました。詳細は 別の回答 にあります。
  • Stream#parallel()では、オプションのスケジューラを受け入れるほとんどのRxJavaメソッドとは異なり、使用するスレッドプールを指定できません。 JVMのallストリームインスタンスは同じfork-joinプールを使用するため、.parallel()を追加すると、プログラムの別のモジュールの動作に誤って影響する可能性があります
  • ストリームには、Observable#interval()Observable#window()などの時間関連の操作がありません。これは主に、ストリームがプルベースであるためです
  • ストリームは、RxJavaと比較して制限された操作セットを提供します。例えば。ストリームにはカットオフ操作がありません(takeWhile()takeUntil()); Stream#anyMatch()を使用する回避策は制限されています。端末操作であるため、ストリームごとに複数回使用することはできません。
  • JDK 8の時点ではStream#Zip操作はありません。これは時々非常に便利です
  • ストリームを自分で構築するのは難しいですが、Observableは多くの方法で構築できます EDIT:コメントで述べたように、Streamを構築する方法があります。ただし、非端子短絡はないため、eはできません。 g。ファイル内の行のストリームを簡単に生成します(JDKはすぐに使用できるFiles#linesとBufferedReader#linesを提供し、他の同様のシナリオはIteratorからStreamを構築することで管理できます)。
  • Observableはリソース管理機能(Observable#using())を提供します。 IOストリームまたはミューテックスでラップし、ユーザーがリソースを解放することを忘れないようにしてください-サブスクリプションの終了時に自動的に破棄されます。ストリームにはonClose(Runnable)メソッドがありますが、手動またはtry-with-resources経由で呼び出す必要があります。例Files#lines()mustをtry-with-resourcesブロックで囲む必要があることに注意してください。
  • オブザーバブルはすべての方法で同期されます(同じことがStreamsにも当てはまるかどうかは実際にはチェックしませんでした)。これにより、基本操作がスレッドセーフかどうか(バグがない限り、答えは常に「yes」です)かどうかを考える必要はありませんが、コードで必要かどうかに関係なく、同時実行関連のオーバーヘッドが発生します。

まとめ:RxJavaはStreamsとは大きく異なります。実際のRxJavaの代替は、 ReactiveStreams の他の実装です。 g。 Akkaの関連部分。

更新Stream#parallelにデフォルト以外のfork-joinプールを使用するトリックがあります。 Java 8並列ストリームのカスタムスレッドプール を参照してください。

更新。上記のすべては、RxJava 1.xの経験に基づいています。 RxJava 2.xはここにあります であるため、この回答は古くなっている可能性があります。

138
Kirill Gamazkov

Java 8 StreamとRxJavaはかなり似ています。似たような演算子(フィルター、マップ、flatMap ...)がありますが、同じ使用法では構築されていません。

RxJavaを使用して非同期タスクを実行できます。

Java 8ストリームを使用すると、コレクションのアイテムを走査します。

RxJava(コレクションのトラバースアイテム)でほぼ同じことを実行できますが、RxJavaは同時タスクに焦点を当てているため、...、同期、ラッチを使用するため、RxJavaを使用する同じタスクは、 Java 8ストリーム。

RxJavaはCompletableFutureと比較できますが、それだけで複数の値を計算できます。

46
dwursteisen

技術的および概念的な違いがいくつかあります。たとえば、Java 8ストリームは単一使用、プルベース、同期の値シーケンスです。値。 RxJavaはJava 6+を対象としており、Androidでも動作します。

35
akarnokd

Java 8 Streamsはプルベースです。各アイテムを消費するJava 8ストリームを反復処理します。そして、それは無限のストリームかもしれません。

RXJava Observableはデフォルトでプッシュベースです。 Observableをサブスクライブすると、次のアイテムが到着したとき(onNext)、ストリームが完了したとき(onCompleted)、またはエラーが発生したとき(onError)に通知されます。 Observableを使用するとonNextonCompletedonErrorイベントを受け取るため、異なるObservablesを新しいものに結合するなどの強力な機能を実行できます(Zipmergeconcat)。他にできることは、キャッシング、スロットリングなどです。そして、異なる言語(RxJava、C#のRX、RxJS、...)でほぼ同じAPIを使用します。

デフォルトでは、RxJavaはシングルスレッドです。スケジューラの使用を開始しない限り、すべてが同じスレッドで発生します。

29
Bart De Neuter

既存の答えは包括的で正しいものですが、初心者向けの明確な例が不足しています。 「プッシュ/プルベース」や「再観察可能」などの用語の背景に具体的な説明を入れてください。 Observable(これは天国のためのストリームです)という用語が嫌いなので、単にJ8対RXストリームを参照します。

整数のリストを考えてください。

digits = [1,2,3,4,5]

J8 Streamは、コレクションを変更するユーティリティです。たとえば、偶数桁は次のように抽出できます。

evens = digits.stream().filter(x -> x%2).collect(Collectors.toList())

これは基本的にPythonの map、filter、reduce であり、Javaに非常に素晴らしい(そして長い間待ち望まれていた)追加機能です。しかし、数字が事前に収集されていない場合-アプリの実行中に数字がストリーミングされている場合-偶数をリアルタイムでフィルタリングできますか?.

アプリの実行中に別のスレッドプロセスがランダムに整数を出力していると想像してください(---は時間を示します)

digits = 12345---6------7--8--9-10--------11--12

RXでは、evencanreactが新しい各桁に反応し、リアルタイムでフィルターを適用します

even = -2-4-----6---------8----10------------12

入力および出力リストを保存する必要はありません。出力リストをwantしたい場合は、ストリーミングも問題ありません。実際、 すべてがストリームです。

evens_stored = even.collect()  

これが、「ステートレス」や「機能」などの用語がRXにより関連している理由です。

25
Adam Hughes

RxJavaは reactive streams Initiative とも密接に関連しており、それをリアクティブストリームAPIの単純な実装と見なします(例: Akka streams implementation と比較)。主な違いは、リアクティブストリームがバックプレッシャーを処理できるように設計されていることですが、リアクティブストリームのページを見ると、アイデアが得られます。彼らは目標を非常によく説明しており、ストリームは reactive manifesto とも密接に関連しています。

Java 8ストリームは、ほとんど無制限のコレクションの実装であり、 Scala Stream または Clojure lazy seq と非常に似ています。

4
Niclas Meier

Java 8 Streamsは、マルチコアアーキテクチャを活用しながら、本当に大きなコレクションを効率的に処理できるようにします。対照的に、RxJavaはデフォルトでシングルスレッドです(スケジューラなし)。したがって、RxJavaは、そのロジックを自分でコーディングしない限り、マルチコアマシンを利用しません。

2
IgorGanapolsky