Skip to content

Project Reactor

Networking & ConcurrencyReactive ProgrammingJava

What it is

Project Reactor is a reactive library for building non-blocking, asynchronous, and event-driven applications on the JVM. It provides types like Mono and Flux to handle zero-to-one and zero-to-many reactive sequences respectively, following the Reactive Streams specification.

Project Reactor provides reactive types like Flux and Mono, operators for transformations, filtering, combining, error handling, and scheduling. It integrates seamlessly with Spring WebFlux and reactive databases for end-to-end non-blocking applications.

Installation

Add dependency in pom.xml: <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> <version>3.5.9</version> </dependency>

Getting started

The smallest useful thing you can do with it, and what each part means.

Creating a Mono
import reactor.core.publisher.Mono;

Mono<String> mono = Mono.just("Hello Reactor");
mono.subscribe(System.out::println);
Creates a Mono that emits a single value and prints it.
Creating a Flux
import reactor.core.publisher.Flux;

Flux<Integer> flux = Flux.just(1, 2, 3, 4);
flux.subscribe(System.out::println);
Creates a Flux that emits multiple values and prints each one.

Advanced usage

Where the library earns its place over a simpler alternative.

Transforming data with map
Flux<Integer> numbers = Flux.just(1, 2, 3, 4);
numbers.map(x -> x * x).subscribe(System.out::println);
Applies a transformation to each emitted value using the map operator.
Filtering data
Flux<Integer> numbers = Flux.range(1, 10);
numbers.filter(x -> x % 2 == 0).subscribe(System.out::println);
Filters even numbers from a sequence using the filter operator.
Combining sequences
Flux<String> flux1 = Flux.just("A", "B");
Flux<String> flux2 = Flux.just("1", "2");
Flux.zip(flux1, flux2, (a,b) -> a + b).subscribe(System.out::println);
Combines two sequences element-wise using zip.
Error handling
Flux<Integer> numbers = Flux.just(1, 0, 2);
numbers.map(x -> 10 / x).onErrorReturn(-1).subscribe(System.out::println);
Handles division by zero errors and provides a fallback value.
Scheduling and threading
Flux.range(1, 5)
    .publishOn(Schedulers.parallel())
    .map(x -> x * 2)
    .subscribe(System.out::println);
Executes the Flux operations on a parallel scheduler for non-blocking concurrency.

Errors and fixes

The failures you are most likely to hit, and what actually resolves them.

OnErrorNotImplementedException
Occurs when a reactive stream emits an error but no error handler is defined. Always provide onError handlers.
IllegalStateException
Occurs when subscribing multiple times to a single-use Mono or Flux improperly. Ensure proper usage.
NullPointerException
Reactor does not allow null values to be emitted. Use Mono.empty() or Flux.empty() instead of null.

Best practices

  • Use Mono for single-value sequences and Flux for multiple-value sequences.
  • Avoid blocking calls inside reactive pipelines to maintain non-blocking behavior.
  • Handle errors gracefully with onErrorReturn, onErrorResume, or retry operators.
  • Use proper Schedulers for asynchronous execution and resource management.
  • Integrate with Spring WebFlux or reactive database clients for end-to-end reactive applications.

Background

Why it exists, and what it was reacting to.

Project Reactor was developed by Pivotal (now part of VMware) to provide a fully reactive foundation for Java applications, particularly in Spring ecosystems. It is widely used in reactive web applications, microservices, and data streaming pipelines to improve scalability, responsiveness, and resource utilization.