RxJava: Reactive Extensions for the JVM
RxJava is the Java implementation of ReactiveX: a library for composing async, event-based code as observable sequences instead of nested callbacks. It earns its keep once you're juggling more than one async source — background work, network calls, UI updates — because flatMap and Schedulers give one vocabulary for it. The catch: a five-operator chain takes practice to read, and RxJava 4 renames the package, so upgrading from 3.x isn't free.
What is RxJava
RxJava is a Java VM library implementing ReactiveX, letting you compose async, event-based programs as observable sequences instead of chains of callbacks. It extends the observer pattern with operators — map, filter, flatMap, and dozens more — that transform, combine, and schedule data streams declaratively while RxJava handles thread-safety underneath. It ships as a plain JVM dependency, no separate framework required.
Core reactive types and operators
- ✓Flowable and Observable model 0..N item streams; only Flowable adds Reactive-Streams-compatible backpressure, while Observable stays unbounded for short, GUI-style sequences.
- ✓Single, Maybe, and Completable cover the single-value and no-value cases — exactly one item or error, zero-or-one item, or a bare completion/error signal — without forcing backpressure onto flows that don't need it.
- ✓Schedulers replace raw threads with a swappable abstraction.
- ✓computation() runs CPU-bound work, cached() runs blocking I/O (replacing the deprecated io()), and the new virtual() runs blocking work on virtual threads instead of native OS threads.
- ✓Operators like flatMap, concatMap, and concatMapEager compose sequences declaratively, including parallel processing via Flowable.parallel() and ParallelFlowable.
- ✓A documented three-phase lifecycle — assembly time, subscription time, runtime — separates building a pipeline from running it, which is why deferred sources like Single.defer() matter for values computed after assembly.
- ✓The 4.x line adds a new Streamable<T> type built on virtual blocking and CompletionStage state machines, marked in the README as still in progress.
Common RxJava use cases
- •Running a blocking computation or network call on a background thread with subscribeOn() and delivering the result on a UI or single-threaded scheduler with observeOn().
- •Fanning a source flow out into per-item async calls with flatMap and merging the results back into one stream, useful for calling a second service per item returned by a first service.
- •Modeling event-driven UI or GUI interactions as Observable sequences on Android or Swing/JavaFX schedulers rather than raw listener callbacks.
- •Chaining dependent async steps (call A, then use its result to call B, then C) as a flatMap pipeline instead of nested callback handlers.
Strengths
- ✓A small, well-defined set of base types (Flowable, Observable, Single, Maybe, Completable, Streamable) maps cleanly onto the shape of the problem — you don't reach for one all-purpose type for every situation.
- ✓Schedulers give you an explicit, swappable abstraction over threading instead of hand-managed ExecutorServices, and RxJava lets you wrap any existing Executor into one via Schedulers.from().
- ✓Flowable's backpressure implementation follows the Reactive Streams spec and includes a Test Compatibility Kit, so it interoperates with other Reactive Streams-based libraries instead of being a closed dialect.
- ✓No third-party runtime dependency, per the README, which keeps the dependency footprint predictable in a Gradle or Maven build.
Known limitations
- △The operator vocabulary is large and the learning curve is steep — reading a five-operator chain fluently, and debugging a stack trace that runs through it, takes real practice.
- △RxJava 4 renames the package to io.reactivex.rxjava4 and moves base classes under io.reactivex.rxjava4.core, so upgrading from RxJava 3 isn't a drop-in swap — the README says 3.x support will be scaled back over time, with continued support offered for about a year after the 4.x release.
- △Several 4.x features are marked in the README as still in progress or uncertain — Streamable<T>, record-based operator configurations, and OSGi support are flagged with 'in progress' or 'question mark' status rather than finished.
- △Android compatibility depends on your API level and available desugaring, per the README — it isn't a guaranteed drop-in on every Android target.
Alternatives to RxJava
Frequently asked questions
RxJava 4 moves the library's packages to io.reactivex.rxjava4 (base classes now live under io.reactivex.rxjava4.core), targets a native Java implementation with virtual thread support, and drops the requirement for a third-party runtime library. The README says RxJava 3.x support will be scaled back over time, with continued support offered for about a year after the 4.x release.
RxJava supports backpressure through its Flowable type, which follows the Reactive Streams specification so consumers can signal how many items they're ready to process. Observable, by contrast, is meant for short or GUI-style sequences and does not apply backpressure — Single, Maybe, and Completable don't need it since they carry at most one item.
The RxJava README tracks 4.0.0 as a milestone rather than a stated production-readiness claim, and some 4.x features — including the new Streamable type and record-based configurations — are documented as still in progress. Teams that need a settled API may prefer to stay on 3.x, which the README says keeps receiving support for about a year after 4.x ships.
RxJava provides six core types: Flowable and Observable for streams of zero to many items (Flowable adds backpressure), Single for exactly one item or an error, Maybe for zero or one item or an error, Completable for a bare completion or error signal with no items, and the newer Streamable type built around virtual threads and backpressure.
RxJava can run on Android, but the README notes that compatibility depends on your Android API level and what desugaring tools are available for the newer Java language features RxJava 4 targets. RxJava also ships Android-specific schedulers like AndroidSchedulers.mainThread() for dispatching results back to the UI thread.
RxJava is licensed under Apache-2.0, a permissive open-source license that allows commercial and closed-source use.
The problem it solves
Coordinating multiple asynchronous operations in Java — a network call that triggers another network call, a UI update that has to wait for a background computation, a stream of events that needs debouncing — usually degenerates into nested callbacks, manually managed thread pools, and ad hoc synchronization that's hard to test. RxJava replaces that with a small set of base types (Flowable, Observable, Single, Maybe, Completable) and Schedulers that abstract the thread underneath, so you describe what should happen to the data instead of wiring executors and locks by hand.
How to install / try
Add RxJava 4 as a Gradle dependency: implementation "io.reactivex.rxjava4:rxjava:4.x.y", replacing x.y with the actual version numbers (Maven users add the equivalent io.reactivex.rxjava4:rxjava coordinate). There's no third-party runtime library required beyond that, per the README. Note that 4.x moves the package to io.reactivex.rxjava4, so it isn't a drop-in swap for a project already pinned to RxJava 3's io.reactivex.rxjava3 packages.
How to use
A minimal RxJava program looks like: Flowable.just("Hello world").subscribe(System.out::println); — RxJava 4's base classes live under io.reactivex.rxjava4.core, so imports change from earlier major versions. From there, most real code follows the pattern in the README's background-computation example: run blocking work with .subscribeOn(Schedulers.cached()) (the replacement for the deprecated Schedulers.io()) and deliver results on another thread with .observeOn(). Because pipelines are built at "assembly time" and only start moving data once you call subscribe(), a value like Single.just(...) placed inside a chain can be evaluated too early — the README's fix is Single.defer(...) or Single.fromCallable(...) to postpone evaluation until runtime.
Who should try it — and who should skip
Reach for RxJava if you're on the JVM and already juggling more than one asynchronous source — background computation plus network calls plus UI updates — and want a single vocabulary (operators, Schedulers) to coordinate them instead of nested callbacks. Skip it for a single async call or two; CompletableFuture or plain coroutines/Structured Concurrency in modern Java cover that without the operator-chain learning curve. Teams mid-migration from RxJava 3 should also weigh the package rename in 4.x (io.reactivex.rxjava3 to io.reactivex.rxjava4) before committing, since it isn't a drop-in upgrade.
Related repositories
Is RxJava worth your time?
ChatGPT, Claude and Perplexity can all read this page. Ask one of them what it makes of RxJava.
