本文已参与「新人创作礼」活动,一起开启掘金创作之路。
窗口抛弃
相似于groupBy, 操作符window发射的内部响应序列应该在外部序列取消的时候(例如, 只和有限的窗口集工作)依然保持接收数据项. 相似的, 当所有的窗口消费者取消的时候, 初始源也应该取消.
然而, 在2.x中, 没有任何机制强制消费内部源, 由此窗口只是简单地全部忽略掉, 这阻止了初始源的取消, 也可能导致源泄露.
有了3.x, 所有window操作符已经被修改了, 所以当它发射组时, 下游必须同步地订阅它. 否则, 窗口会被认为是"被抛弃"从而终止掉. 这种情况下, 被抛弃的窗口不能阻止初始流的取消. 如果后来的消费者依然订阅这个窗口, 触发窗口创建的数据项可能依然可用.
同步订阅意味着下面的流设置将会导致抛弃:
窗口抛弃示例
// observeOn creates a time gap between window emission
// and subscription
source.window(10, 5)
.observeOn(Schedulers.computation())
.flatMap(g -> g)
// subscribeOn creates a time gap too
source.window(1, TimeUnit.SECONDS)
.flatMap(g -> g.subscribeOn(Schedulers.computation()))
因为窗口本质上是热源, 因此可以通过observeOn将数据项的处理安全地移动到别的线程:
source.window(1, TimeUnit.SECONDS)
.flatMap(g ->
g.observeOn(Schedulers.computation())
.map(v -> v + 1)
)
生成CompositeException cause
在1.x和2.x中, 调用方法CompositeException.getCause()导致从内部聚合异常列表中生成异常链. 这主要是因为Java 6缺乏Java 7+的异常抑制特性. 然而, 这些实现可能正在转换异常, 或者, 有时候, 完全不能建立起异常链. 鉴于该方法最初贡献的来源, 在2.x中修复该方法的问题是有风险的.
有了3.x, 该方法构造了一个异常原因,当该异常请求stacktrace时,会在不触及聚合异常的情况下生成输出(这个操作是IDE友好的, 应该也是可以导航的):
栈迹示例
Multiple exceptions (2)
|-- io.reactivex.rxjava3.exceptions.TestException: ex3
at io.reactivex.rxjava3.exceptions.CompositeExceptionTest.nestedMultilineMessage(CompositeExceptionTest.java:341)
|-- io.reactivex.rxjava3.exceptions.TestException: ex4
at io.reactivex.rxjava3.exceptions.CompositeExceptionTest.nestedMultilineMessage(CompositeExceptionTest.java:342)
|-- io.reactivex.rxjava3.exceptions.CompositeException: 2 exceptions occurred.
at io.reactivex.rxjava3.exceptions.CompositeExceptionTest.nestedMultilineMessage(CompositeExceptionTest.java:337)
|-- io.reactivex.rxjava3.exceptions.CompositeException.ExceptionOverview:
Multiple exceptions (2)
|-- io.reactivex.rxjava3.exceptions.TestException: ex1
at io.reactivex.rxjava3.exceptions.CompositeExceptionTest.nestedMultilineMessage(CompositeExceptionTest.java:335)
|-- io.reactivex.rxjava3.exceptions.TestException: ex2
at io.reactivex.rxjava3.exceptions.CompositeExceptionTest.nestedMultilineMessage(CompositeExceptionTest.java:336)
参数验证异常的更改
2.x中的一些标准操作符在对应的参数非法时会抛出IndexOutOfBoundsException. 为了与其它参数验证异常保持一致, 下面的操作符现在抛出了IllegalArgumentException:
skipskipLasttakeLasttakeLastTimed
预先取消from回调
在2.x, 取消通过fromRunnable和fromAction创建的序列是与其它fromX序列不一致的, 在下游立即取消/销毁该序列的时候.
在3.x中, 这种预先取消将不会执行给定的回调.
from回调示例
Runnable run = mock(Runnable.class);
Completable.fromRunnable(run)
.test(true); // cancel upfront
verify(run, never()).run();
使用cleanup次序
操作符using有eager参数来决定什么时候源应该被清理: true意味着在终止之前而false则意味着在终止之后. 不幸的是, 此设置不会影响取消donwstream时的清理顺序, 并且总是在取消上游之前清理资源.
在3.x中, 在序列终止或者取消的时候, 清理顺序现在是一致的: true意味着终止之前或者取消上游之前, false意味着终止之后或者取消上游之后.