Reactive Programming in Java: Complete Guide with Examples

Jun 18, 2025

Follow us on


Learn Reactive Programming in Java using Project Reactor, RxJava, and Spring WebFlux. Master Mono, Flux, observables, and asynchronous data streams with real-world code examples.

Introduction

In today's world of cloud-native and event-driven architectures, the traditional synchronous and blocking style of programming often fails to deliver the performance, scalability, and responsiveness demanded by modern applications. This is where Reactive Programming comes into play.

Reactive programming in Java has evolved significantly, primarily driven by libraries and frameworks like Project Reactor, RxJava, and Spring WebFlux. This guide introduces reactive programming concepts and demonstrates how to use them in Java applications effectively.

What is Reactive Programming?

Reactive Programming is a paradigm that focuses on asynchronous data streams and the propagation of changes. Rather than pulling data in a blocking manner, data is pushed to the application as events occur.

Key principles of reactive programming:

  • Asynchronous: Operations are non-blocking.
  • Event-driven: Data is pushed as events.
  • Backpressure: The consumer can signal when it cannot handle more data.
  • Responsive: Systems react in a timely manner.

Reactive Streams Specification

Reactive programming in Java is standardized via the Reactive Streams specification, which includes four key interfaces:

  • Publisher<T>
  • Subscriber<T>
  • Subscription
  • Processor<T, R>

Java 9 introduced these in the java.util.concurrent.Flow package.

Project Reactor

Project Reactor is a reactive library for building non-blocking applications on the JVM. It's the foundation for Spring WebFlux and provides two main types:

  • Mono<T>: Represents a stream with 0 or 1 element.
  • Flux<T>: Represents a stream of 0 to N elements.

Mono Example

Mono<String> mono = Mono.just("Hello Reactive World");
mono.subscribe(System.out::println);

Flux Example

Flux<Integer> numbers = Flux.range(1, 5);
numbers.subscribe(System.out::println);

RxJava Overview

RxJava is another popular reactive library for Java. It provides types like Observable, Single, Maybe, and Flowable.

RxJava Example

Observable<String> observable = Observable.just("RxJava is cool!");
observable.subscribe(System.out::println);

Flowable is used when you want backpressure support in RxJava.

Reactive Programming vs Traditional Programming

Traditional Reactive
Blocking I/O Non-blocking I/O
Thread per request Event loop model
Push updates manually Observe data streams
Synchronous APIs Asynchronous APIs

Spring WebFlux: Reactive Web Applications

Spring WebFlux is part of the Spring Framework 5+ and is built for reactive applications using Reactor.

Controller Example

@RestController
@RequestMapping("/api/reactive")
public class ReactiveController {

    @GetMapping("/mono")
    public Mono<String> getMono() {
        return Mono.just("Mono response");
    }

    @GetMapping("/flux")
    public Flux<String> getFlux() {
        return Flux.just("One", "Two", "Three");
    }
}

Working with Backpressure

Backpressure is how a subscriber controls the flow of data. This prevents overwhelming the consumer if the publisher is emitting data too quickly.

Flux.range(1, 1000)
    .onBackpressureBuffer(10)
    .subscribe(System.out::println);

Error Handling in Reactive Streams

Reactive libraries provide powerful error handling operators like onErrorResume, onErrorReturn, and retry.

Mono.just("abc")
    .map(str -> Integer.parseInt(str))  // will throw NumberFormatException
    .onErrorReturn(-1)
    .subscribe(System.out::println);

Chaining and Transformations

Flux.just(1, 2, 3)
    .map(i -> i * i)
    .filter(i -> i % 2 == 0)
    .subscribe(System.out::println);

Combining Streams

Flux<String> flux1 = Flux.just("A", "B");
Flux<String> flux2 = Flux.just("C", "D");

Flux.merge(flux1, flux2)
    .subscribe(System.out::println);

Delay and Scheduling

Flux.interval(Duration.ofSeconds(1))
    .take(5)
    .subscribe(System.out::println);

Testing Reactive Streams

@Test
public void testMono() {
    StepVerifier.create(Mono.just("test"))
        .expectNext("test")
        .verifyComplete();
}

Use Cases for Reactive Java

  • Streaming APIs
  • Chat applications
  • IoT data pipelines
  • Stock market and sensor data processing
  • Database access with R2DBC or MongoDB Reactive

Best Practices

  • Never block inside a reactive stream
  • Use Schedulers.boundedElastic() for I/O
  • Keep the chain clean and readable
  • Use operators wisely (e.g., flatMap, concatMap)
  • Write unit tests using StepVerifier

Conclusion

Reactive Programming in Java is no longer just a trend — it’s becoming the foundation of scalable, modern software. With libraries like Project Reactor, RxJava, and frameworks like Spring WebFlux, Java developers are fully equipped to build responsive, event-driven systems.

Whether you're creating APIs, microservices, or real-time applications, adopting reactive programming gives you a competitive edge. Start simple with Mono and Flux, understand backpressure, and slowly transition critical parts of your system to reactive design for best results.

Next Steps:

  • Learn Project Reactor deeper
  • Build a REST API with Spring WebFlux
  • Use reactive database drivers like R2DBC
  • Experiment with RxJava's advanced operators

© 2025 TtimesNow. All rights reserved.