Java 8流和RxJava可观察量之间的差异

时间:2015-05-13 13:54:00

标签: java-8 java-stream rx-java observable

Java 8流是否与RxJava observables类似?

Java 8流定义:

  

java.util.stream包中的类提供了一个Stream API   支持元素流上的功能样式操作。

7 个答案:

答案 0 :(得分:131)

TL; DR :所有序列/流处理库都为管道构建提供了非常相似的API。不同之处在于用于处理多线程和管道组合的API。

RxJava与Stream完全不同。在所有JDK事物中,最接近rx.Observable的可能是 java.util.stream.Collector Stream + CompletableFuture组合(其代价是处理额外的monad层,即必须处理之间的转换) Stream<CompletableFuture<T>>CompletableFuture<Stream<T>>)。

Observable和Stream之间存在显着差异:

  • Streams是基于拉式的,Observables是基于推送的。这可能听起来过于抽象,但它具有非常具体的重大后果。
  • Stream只能使用一次,Observable可以多次订阅
  • Stream#parallel()将序列拆分为分区,Observable#subscribeOn()Observable#observeOn()不分区;使用Observable模拟Stream#parallel()行为很棘手,它曾经有.parallel()方法,但是这种方法造成了很多混乱,以至于.parallel()支持被移动到github上的独立存储库RxJavaParallel。更多详情请见another answer
  • Stream#parallel()不允许指定要使用的线程池,这与大多数接受可选Scheduler的RxJava方法不同。由于 JVM中的所有流实例使用相同的fork-join池,因此添加.parallel()可能会意外影响程序的另一个模块中的行为
  • Streams缺少与时间相关的操作,例如Observable#interval()Observable#window()和其他许多操作;这主要是因为Streams是基于拉力的
  • 与RxJava相比,Streams提供了一组受限制的操作。例如。流缺乏截止操作(takeWhile()takeUntil());使用Stream#anyMatch()的变通方法是有限的:它是终端操作,因此您无法在每个流中使用它
  • 从JDK 8开始,没有Stream#zip操作,有时非常有用
  • Streams很难自己构建,Observable可以通过多种方式构建 编辑:如评论中所述,有一些方法可以构建Stream。但是,由于没有非终端短路,你可以这样做。 G。轻松生成文件中的行流(JDK提供了开箱即用的Files#行和BufferedReader#行,其他类似的方案可以通过从Iterator构造Stream来管理)。
  • Observable提供资源管理工具(Observable#using());你可以用它包装IO流或互斥,并确保用户不会忘记释放资源 - 它将在订阅终止时自动处理; Stream有onClose(Runnable)方法,但您必须手动或通过try-with-resources调用它。 E. g。你必须记住,文件#lines()必须包含在try-with-resources块中。
  • Observable一直同步(我实际上没有检查Streams是否也是如此)。这使您不必考虑基本操作是否是线程安全的(答案总是“是”,除非出现“错误”),但无论您的代码是否存在,并发相关的开销都会存在需要与否。

综述:RxJava与Streams显着不同。 Real RxJava替代品是ReactiveStreams的其他实现,e。 G。阿卡的相关部分。

<强>更新即可。为Stream#parallel使用非默认的fork-join池有诀窍,请参阅Custom thread pool in Java 8 parallel stream

<强>更新即可。以上所有内容均基于RxJava 1.x的经验。现在RxJava 2.x is here,这个答案可能已经过时了。

答案 1 :(得分:46)

Java 8 Stream和RxJava看起来非常相似。它们具有相似的运算符(filter,map,flatMap ......),但不是为相同的用法而构建的。

您可以使用RxJava执行asynchonus任务。

使用Java 8流,您将遍历集合中的项目。

你可以在RxJava(遍历集合的项目)中做同样的事情,但是,由于RxJava专注于并发任务,...,它使用同步,锁存,......所以使用RxJava的相同任务可能比Java 8流慢。

可以将RxJava与CompletableFuture进行比较,但这样可以计算的不仅仅是一个值。

答案 2 :(得分:35)

存在一些技术和概念上的差异,例如,Java 8流是单用的,基于拉的,同步的值序列,而RxJava Observable是可重新观察的,基于自适应推送的,可能是异步的值序列。 RxJava针对Java 6+,也适用于Android。

答案 3 :(得分:29)

Java 8 Streams是基于拉取的。您遍历消耗每个项目的Java 8流。它可能是无穷无尽的。

RXJava Observable默认是基于推送的。您订阅了Observable,当下一个项目到达时(onNext),或者流完成(onCompleted)或发生错误(onError)时,您将收到通知。 因为Observable您收到了onNextonCompletedonError个事件,所以您可以执行一些强大的功能,例如将不同的Observable组合到新的zipmerge 1}},concatbefore do VCR.turn_off! WebMock.allow_net_connect! end after do VCR.turn_on! WebMock.disable_net_connect! end )。你可以做的其他事情是缓存,节流,...... 它在不同语言中使用或多或少相同的API(RxJava,C#中的RX,RxJS,......)

默认情况下,RxJava是单线程的。除非您开始使用Scheduler,否则一切都将在同一个线程上发生。

答案 4 :(得分:22)

现有的答案是全面和正确的,但缺乏明确的初学者榜样。请允许我在“推/拉”和“可重新观察”等术语背后加上一些具体内容。 注意:我讨厌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中,even可以对每个新数字做出反应并实时应用过滤器

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

无需存储输入和输出列表。如果您想要输出列表,那么也没有问题可以流式传输。事实上,everything is a stream.

evens_stored = even.collect()  

这就是“无状态”和“功能”等术语与RX

更相关的原因

答案 5 :(得分:4)

RxJava也与reactive streams initiative密切相关,并将其视为反应流API的简单实现(例如与Akka streams implementation相比)。主要区别在于,反应流设计为能够处理背压,但如果您查看反应流页面,您将会得到这个想法。他们很好地描述了他们的目标,并且流也与the reactive manifesto密切相关。

Java 8流几乎是无界集合的实现,非常类似于Scala StreamClojure lazy seq

答案 6 :(得分:2)

Java 8 Streams可以有效地处理真正大型的集合,同时利用多核架构。相比之下,RxJava默认是单线程的(没有Schedulers)。所以除非你自己编写逻辑,否则RxJava不会利用多核机器。