Реактивное программирование в Java: библиотеки Project Reactor и RxJava

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Реактивное программирование в Java: Project Reactor и RxJava

Реактивное программирование — это парадигма разработки, ориентированная на обработку асинхронных потоков данных и событий. В Java эта парадигма получила широкое распространение благодаря библиотекам, реализующим спецификацию Reactive Streams. Две самые популярные реализации — Project Reactor (основа Spring WebFlux) и RxJava (Reactive Extensions for Java).

В отличие от традиционного императивного подхода, реактивное программирование позволяет эффективно работать с большими объемами данных, не блокируя потоки выполнения. Это особенно важно для современных высоконагруженных веб-приложений, микросервисов и систем реального времени.

Основные концепции реактивного программирования

В основе реактивного подхода лежат три ключевых понятия:

  • Observable (издатель) — источник данных, который может генерировать события (элементы, ошибки, завершение).
  • Observer (подписчик) — потребитель данных, который реагирует на события.
  • Операторы — функции преобразования потоков (map, filter, flatMap, combineLatest и др.).

Реактивные потоки следуют принципу backpressure (обратное давление): подписчик может сообщить издателю, сколько элементов он готов обработать, что предотвращает переполнение памяти.

Project Reactor: Flux и Mono

Project Reactor — это реактивная библиотека от Pivotal (теперь VMware), которая лежит в основе Spring WebFlux. Она предоставляет два основных типа:

  • Flux<T> — поток, который может содержать 0, 1 или много элементов (асинхронная последовательность).
  • Mono<T> — поток, который содержит 0 или 1 элемент (аналог Optional, но асинхронный).

Пример: создание и обработка Flux

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

public class ReactorExample {
    public static void main(String[] args) {
        // Создаем поток из списка
        Flux<String> names = Flux.just("Alice", "Bob", "Charlie", "Diana");

        // Применяем операторы
        names.filter(name -> name.length() > 3)
             .map(String::toUpperCase)
             .subscribe(
                 result -> System.out.println("Получено: " + result),
                 error -> System.err.println("Ошибка: " + error),
                 () -> System.out.println("Поток завершен")
             );

        // Mono — для одного элемента
        Mono<String> greeting = Mono.just("Hello, Reactive!");
        greeting.subscribe(System.out::println);
    }
}

Результат выполнения:

Получено: ALICE
Получено: CHARLIE
Получено: DIANA
Поток завершен
Hello, Reactive!

RxJava: Observable, Flowable и Single

RxJava — это портированная на Java реализация Reactive Extensions (Rx). В версии 3.x (RxJava 3) доступны следующие основные типы:

  • Observable<T> — поток с 0..N элементами, без поддержки backpressure.
  • Flowable<T> — поток с 0..N элементами, с поддержкой backpressure.
  • Single<T> — поток ровно с одним элементом или ошибкой.
  • Maybe<T> — поток с 0 или 1 элементом.
  • Completable — поток без данных, только сигнал завершения или ошибки.

Пример: работа с Observable и операторами

import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;

public class RxJavaExample {
    public static void main(String[] args) {
        // Создаем Observable из диапазона чисел
        Observable<Integer> numbers = Observable.range(1, 5);

        // Применяем цепочку операторов
        numbers
            .filter(n -> n % 2 == 0)      // четные числа
            .map(n -> n * 10)              // умножаем на 10
            .subscribe(
                item -> System.out.println("Элемент: " + item),
                error -> System.err.println("Ошибка: " + error),
                () -> System.out.println("Готово!")
            );

        // Single — для одного результата
        Single<String> single = Single.just("Единственное значение");
        single.subscribe(
            value -> System.out.println("Single: " + value),
            error -> System.err.println("Single error: " + error)
        );
    }
}

Вывод программы:

Элемент: 20
Элемент: 40
Готово!
Single: Единственное значение

Сравнение Project

Рекомендаций