Programação Reativa em Java: Biblioteca Reactor

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Programação Reativa em Java com Project Reactor



Programação reativa é um paradigma de desenvolvimento focado em fluxos de dados assíncronos e propagação de mudanças. Em Java, esse conceito é implementado através da especificação Reactive Streams e sua implementação mais popular — a biblioteca Project Reactor (parte do ecossistema Spring WebFlux).



Diferentemente do código imperativo tradicional, onde o programa executa comandos sequencialmente, a abordagem reativa permite processar dados à medida que chegam, sem bloquear threads de execução. Isso é especialmente importante para sistemas de alta carga, microsserviços e aplicações com grande número de requisições simultâneas.



Componentes principais do Reactor



A biblioteca fornece dois tipos principais de sequências reativas:



  • Mono<T> — representa um fluxo que pode conter 0 ou 1 elemento. Usado para operações assíncronas únicas (ex.: requisição HTTP, obtenção de registro do banco de dados).
  • Flux<T> — representa um fluxo que pode conter de 0 a N elementos. Adequado para coleções, fluxos de eventos ou dados que chegam em partes.


Ambos os tipos implementam a interface Publisher da especificação Reactive Streams e suportam o mecanismo de backpressure (contrapressão) — a capacidade do assinante controlar a velocidade de recebimento dos dados.



Exemplo: criação e processamento de Flux



Vamos considerar um exemplo simples de criação de um fluxo reativo de números e seu processamento:



import reactor.core.publisher.Flux;

public class ReactorExample { public static void main(String[] args) { Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);

numbers .map(n -> n * 2) // transformação .filter(n -> n % 3 == 0) // filtragem .subscribe( data -> System.out.println("Recebido: " + data), error -> System.err.println("Erro: " + error), () -> System.out.println("Finalizado!") ); }}


Neste exemplo:

  • Flux.just() cria um fluxo de cinco números.
  • map() multiplica cada elemento por 2.
  • filter() mantém apenas os números múltiplos de 3.
  • subscribe() inicia o processamento — exibe o resultado, trata erros e sinaliza a conclusão.


Assincronia e trabalho com Mono



O Reactor permite executar operações assíncronas sem bloquear threads. Por exemplo, simulação de uma requisição a um serviço remoto:



import reactor.core.publisher.Mono;import java.time.Duration;

public class AsyncExample { public static void main(String[] args) throws InterruptedException { Mono<String> asyncResult = Mono.fromSupplier(() -> { try { Thread.sleep(1000); // simulação de atraso } catch (InterruptedException e) { e.printStackTrace(); } return "Dados recebidos"; }).subscribeOn(Schedulers.boundedElastic()); // executa em outra thread

System.out.println("Requisição enviada..."); asyncResult.subscribe(System.out::println); Thread.sleep(2000); // aguarda a conclusão }}


Ponto-chave: a chamada .subscribeOn() transfere a execução da operação custosa para uma thread separada, sem bloquear a principal. O assinante receberá o resultado de forma assíncrona.



Tratamento de erros em fluxos reativos



Diferentemente do try-catch, na programação reativa os erros são tratados através de operadores:



Flux<String> fluxWithError = Flux.just("A", "B", "C")    .map(s -> {        if ("B".equals(s)) t                    

Recommendations