What’s New in RxJava 3

8 min


In the spring of 2020, a fresh version of the framework was released. Rxjava – RxJava 3. Let’s look at what the main changes are, how you can upgrade from RxJava 2 to the new version, and whether to migrate at all.

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

Disclaimer: This article is based on github reviewIn addition, we share the impressions of our mobile developers from RxJava 3, but do not claim to be exhaustive research – because the new version came out recently and there is not much practical experience. If you have additions, write in the comments, we will be happy to discuss)

Key Changes in RxJava 3

So what we see in RxJava 3:

  • The basic version of Java is now increased to 8 *;
  • Support has been added for such language features as:

– Streams
– Stream Collectors
– Optional
– CompletableFeature

*For use 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 large number of overloads, can always be replaced with time + unit;
  • java.util.function – cannot throw exceptions, while overloads can create unnecessary “ambiguity”.

The package structure has also changed:

The presented changes can be divided into 2 groups:

  1. Behavioral changes
  2. API changes

Behavioral changes

  • All errors will be processed.

Earlier, one of the problems of RxJava 2 was that in some cases errors could be lost and not be processed. Now in RxJava 3, unsubscribing from a source that may throw an error initiates the forwarding of this error to the common error handler via RxJavaPlugins.onError ()

  • Connectable.reset ()

There was a problem with hot sources in RxJava 2: when receiving a ConnectableObservable terminal event, new connections ignored all elements and received only the terminate event.

RxJava 3 introduced the ConnectableObservable reset function with the reset () function to enable newly connected subscribers to process data.

  • Ability to pause Flowable.publish

In RxJava 3, after receiving a certain number of values, Flowable.publish is paused, while the remaining elements are available to the following 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 raised.

  • CompositeException.getCause ()

Earlier in RxJava 2, the getCause () method sometimes significantly loaded the memory, calling the initCause method for each exception, it was unstable, it did not always generate an exception chain.

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

  • Parameter validation exceptions changed

With an invalid parameter, some operators will now throw an IllegalArgumentException instead of an IndexOutOfBoundsException:

– skip
– skipLast
– takeLast
– takeLastTimed

  • Pre-Closing Sources for fromX ()

The fromAction () and fromRunnable () libraries became consistent with the rest of the fromX () calls. Callbacks fromRunnable () and fromAction () will now be closed instantly with the corresponding call. In RxJava 2, these statements were closed after the execution of the lambda body passed to the parameters.

  • The procedure for clearing a resource when using using ()

The using () operator has a parameter responsible for when the used resource will be cleared (true – before completion, false – after). In the earlier version of the library, this parameter was ignored, and the resource was always cleared until the terminal state was obtained, but in RxJava 3 everything works correctly.

API changes

  • Exception handling of functional interfaces of the new version of the library is expanded from Exception to Throwable
  • New Types: Supplier

In RxJava 3, due to the extension of functional interface exceptions from Exception to Throwable, a new type of Supplier is introduced – an analogue of Callable, but with throws Throwable

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

  • Relocated Components

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

As it was before:

It became:

  • In order to reduce warnings, the DisposableContainer class that was used inside CompositeDisposable has been 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 ()

  • In the new version of the library, the operator concatMap () for flexibility of flow control was overloaded Scheduler’om

  • There was an update of various types of data sources fromX () – operators

  • Operator toFuture () now available for use in Maybe and Completable
  • Operator ofType () now available for use in Maybe and Single
  • Operator doOnLifecycle () now available for use in Maybe, Single and Completable
  • The concatMapX () operator (X is another type of data source) is now available for use in Maybe and Single
  • Operator concatDelayError () now available for use in Maybe, Single and Completable
  • Operator mergeArray () now available for use in Single

  • Operator startWith () now available for use in all five types of data sources

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)

  • Operator safeSubscribe () now available for use in Maybe, Single and Completable

  • Operator flatMap () now available for use in Single

New with Java8

New operator added fromOptional () for Flowable, Observable and Maybe

New operator added fromStream () for Flowable and Observable

New operator added fromCompletionStage () for all five types of data sources

New operator added mapOptional () for Flowable, Observable, Maybe, and Single. It only skips non-empty values

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

New operators added flatMapStream () and concatMapStream () for Flowable and Observable – allow you to convert each item into a separate stream

New operators added flattenStreamAsFlowable () and flattenStreamAsObservable () for Maybe and Single – equivalent flatMapStream () operators for Observable and Flowable

What is renamed

What is removed from the API

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

subscribe (…, …, …,), replacement – doOnSubscribe ()

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

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

replay (Scheduler), replacement – observeOn (Scheduler)

dematerialize (), replacement – deserialize (Function)

onExceptionResumeNext (), replacement – onErrorResumeNext (Function)

combineLatest () (with vararg parameter), replacement – combineLatestArray ()

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

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

The following methods have also been removed from TestSubscriber and TestObserver:

How to migrate

Many developers note that migrating from RxJava 2 to RxJava 3 is a rather time-consuming process. To make the transition, there are two options:

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

So how to migrate:

  • Actualize work with the API – use analogues of those RxJava 2 methods that were subject to change.
  • It is important to consider that some third-party libraries are still “sitting” on RxJava 2. To simplify the transition, you can take RxJavaBridgethat hides most of the migration under the hood.
  • When used in a Retrofit project, pull up RxJava3CallAdapterFactory or make your own factory to correctly map the response.

Conclusion

We looked at what’s new in RxJava 3. Now let’s try to answer the main question – is it worth migrating at all?

RxJava 3 is practically an improvement to the API. 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 connected with RxJava 2, to work with Java8, you will additionally need to raise minSDK to version 24. Some teams have alternative solutions – for example, use Kotlin Coroutines.

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

Thanks for your attention! We hope you find this material helpful.


0 Comments

Leave a Reply