What's new in RxJava 3

In the spring of 2020, a fresh version of the RxJava framework , RxJava 3, was released. Let's look at what the main changes are, how you can switch from RxJava 2 to the new version, and whether it's worth migrating at all.



Note that there are no global changes in the new version, but support for Java 8 has appeared, and the library has become more convenient to use.







Disclaimer: This article is based on a GitHub review , in addition, we share our mobile developers' impressions of RxJava 3, but we do not pretend to be an exhaustive study - because the new version was released recently and there is not much practical experience yet. If you have any additions, write in the comments, we will be happy to discuss)



Key changes in RxJava 3



So what we see in RxJava 3 :



  • Java base version is now increased to 8 *;
  • There is support for such language features as:


- Streams

- Stream Collectors

- Optional

- CompletableFeature



* To use the Java8 API, you need to raise minSDK to version 24.



In turn, the developers removed support for such features as:



  • java.time.Duration - generates a lot of overloads, can always be replaced with time + unit;
  • java.util.function - Cannot throw exceptions, and overloads can create unnecessary "ambiguity".


The package structure has also changed:







The changes presented can be divided into 2 groups:



  1. Behavioral changes
  2. API changes


Behavioral changes



  • All errors will be processed


Previously, one of the problems with RxJava 2 was that in some cases, errors could get lost and not be handled. Now, in RxJava 3, unsubscribing from a source that might throw an error triggers a throwing of this error into the general error handler via RxJavaPlugins.onError ()







  • Connectable.reset ()


There was a hot springs issue in RxJava 2: when receiving a ConnectableObservable terminal event, new connections ignored all items and only received the terminate event.



RxJava 3 introduces a function to reset the ConnectableObservable state using the reset () function to allow newly connected subscribers to process data.











  • Ability to pause Flowable.publish


In RxJava 3, after a certain number of values ​​are received, the Flowable.publish is paused and the remaining elements are available to subsequent subscribers.







  • Processor.offer () null parameter


If you try to call PublishProcessor.offer (), BehaviourProcessor.offer (), or MulticastProcessor.offer () and pass null, a NullPointerException is thrown instead of passing an error to the onError handler, and a terminal state is triggered.







  • CompositeException.getCause ()


Earlier in RxJava 2, the getCause () method sometimes was a significant memory load, calling the initCause method on each exception, was unstable, and did not always throw an exception chain.



In the new version, this method has been changed from the inside and now generates a chain of errors in the form of a stack trace - by simple formatting of strings.











  • Changed parameter validation exceptions


If the parameter is invalid, some operators will now throw IllegalArgumentException instead of IndexOutOfBoundsException:



- skip

- skipLast

- takeLast

- takeLastTimed



  • Pre-closing sources for fromX ()


The fromAction () and fromRunnable () libraries have become consistent with the rest of the fromX () calls. The fromRunnable () and fromAction () callbacks will now be closed instantly when called accordingly. In RxJava 2, these operators were closed after the end of the execution of the body of the lambda passed to the parameters.







  • Order of resource cleanup when using using ()


The using () statement has a parameter that is responsible for when the used resource will be cleaned up (true - before completion, false - after). In the early version of the library, this parameter was ignored, and the resource was always cleaned up before getting the terminal state, but in RxJava 3 everything works correctly.







API changes



  • Exception handling of functional interfaces of the new version of the library has been extended from Exception to Throwable


  • New types: Supplier


In RxJava 3, in connection with the extension of exceptions of functional interfaces from Exception to Throwable, a new Supplier type was introduced - analogous to Callable, but with throws Throwable







  • In RxJava 3, the operators for converting one data source to another have been changed to specific converters










  • Moved components


Due to the fact that RxJava3 will support the Java8 API, a new solution has come to replace individual factory classes: the methods of these factories have become static methods of the Disposable interface.



As it was before:







Now:





  • In order to reduce warnings, the DisposableContainer class that was used inside the CompositeDisposable is made part of the public API
  • Some of the operators in RxJava 2 were at the experimental stage, and in the third version they became standard operators:


Flowable promotions



dematerialize(Function)



Observable promotions

dematerialize(Function)



Maybe promotions



doOnTerminate(Action)

materialize()



Single promotions



dematerialize(Function)

materialize()



Complectable promotions



delaySubscription(long, TimeUnit)

delaySubscription(long, TimeUnit, Scheduler)

materialize()







































  • fromX()-




















Flowable

startWith(MaybeSource)

startWith(SingleSource)

startWith(ComplectableSource)



Observable

startWith(MaybeSource)

startWith(SingleSource)

startWith(ComplectableSource)



Maybe

startWith(Publisher)

startWith(ObservableSource)

startWith(MaybeSource)

startWith(SingleSource)

startWith(ComplectableSource)



Single

startWith(Publisher)

startWith(ObservableSource)

startWith(MaybeSource)

startWith(SingleSource)

startWith(ComplectableSource)



Complectable

startWith(MaybeSource)

startWith(SingleSource)































Java8





Added new operator fromOptional () for Flowable, Observable and Maybe





Added new operator fromStream () for Flowable and Observable









Added new operator fromCompletionStage () for all five data source types









Added new operator mapOptional () for Flowable, Observable, Maybe and Single. It only allows non-empty values to pass.







Added new blockingStream () operator for Flowable and Observable. The operator represents the data stream as a stream, while it is recommended to close the stream upon completion of work with it in order to prevent all kinds of leaks







Added new operators flatMapStream () andconcatMapStream () for Flowable and Observable - allow each item to be converted into a separate stream







Added new operators flattenStreamAsFlowable () and flattenStreamAsObservable () for Maybe and Single - equivalent flatMapStream () operators for Observable and Flowable







What's renamed





API



Maybe.toSingle (), replacement - Maybe.defaultIfEmpty ()

subscribe (..., ..., ...,), replacement - doOnSubscribe ()

Single.toCompletable (), replacement - Single.ignoreElement ()

Completable.blockingGet (), replacement - Completable .blockingAwait ()

replay (Scheduler), replace - observeOn (Scheduler)

dematerialize (), replace - deserialize (Function)

onExceptionResumeNext (), replace - onErrorResumeNext (Function)

combineLatest () (with vararg parameter), replace - combineLatestArray ()

fromFuture () (with Scheduler parameter), replacement - subscribeOn ()

concatMapIterable () (with buffer parameter), replacement - concatMapIterable (Function)



Also removed the following methods from TestSubscriber and TestObserver:







How to migrate



Many developers note that migrating from RxJava 2 to RxJava 3 is a rather laborious process. There are two options for making the transition:



  • have both versions of the library on your project;
  • perform a full migration to RxJava 3, while you can use a special library .


So how to migrate:



  • To update the work with the API - to use analogs of those RxJava 2 methods that were subject to change.
  • It is important to keep in mind that some third-party libraries are still "sitting" on RxJava 2. To simplify the transition, you can take RxJavaBridge , which hides most of the migration under the hood.
  • Retrofit RxJava3CallAdapterFactory .




We've reviewed what's new in RxJava 3. And now let's try to answer the main question - is it worth migrating at all?



RxJava 3 is practically an API improvement. Due to the fact that there were no fundamental changes, in general there is no need to migrate to the latest version right now. The transition itself requires effort, while many third-party libraries are still associated with RxJava 2, to work with Java8, you will additionally need to raise minSDK to version 24. Some teams also offer alternative solutions, such as using Kotlin Coroutines.



However, it's worth noting that RxJava 2 is now going into “maintenance” mode, which means that there will only be bug fixes from the updates. Support for the second version is expected to end on February 28, 2021.



! , .



All Articles