CompletableFuture em Java: Guia completo para programação assíncrona

Por Gaspar Barancelli Junior em 10 de maio de 2024
Imagem ilustrativa sobre o post CompletableFuture em Java: Guia completo para programação assíncrona

Os CompletableFuture são uma evolução dos tradicionais Future no Java, oferecendo uma abordagem robusta para a programação assíncrona. Neste post, vamos explorar os benefícios, casos de uso e exemplos práticos que ilustram como essa ferramenta pode ser poderosa no desenvolvimento de aplicações Java.

Benefícios do CompletableFuture

  • Não bloqueio: Diferente de outras formas de Future, CompletableFuture permite a execução de callbacks sem bloquear threads, o que melhora a eficiência do uso dos recursos do sistema.

  • Encadeamento de tarefas: Você pode encadear várias operações de forma assíncrona, o que facilita a manipulação de tarefas dependentes.

  • Tratamento de exceções: Oferece mecanismos integrados para lidar com erros de uma maneira mais granular e controlada.

  • Flexibilidade: Permite combinar múltiplas tarefas assíncronas de maneiras complexas, promovendo uma maior modularidade no código.

Casos de Uso

  • Serviços Web Assíncronos: Ideal para desenvolvimento de APIs que necessitam realizar várias chamadas externas ou operações I/O sem bloquear o servidor.

  • Aplicações de Microserviços: Facilita o gerenciamento de múltiplas chamadas a serviços distintos que podem ser executadas em paralelo.

  • Processamento de Dados em Grande Escala: Permite a execução e o gerenciamento de múltiplas tarefas de processamento de dados simultaneamente, otimizando o tempo de resposta.

Exemplos

Utilizando runAsync

Este exemplo demonstra como iniciar uma tarefa assíncrona que não retorna um valor. CompletableFuture.runAsync aceita um Runnable e executa-o em um executor assíncrono, que por padrão é o ForkJoinPool.commonPool().

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    System.out.println("Executando tarefa assíncrona sem retorno.");
});
future.get();  // Aguarda a conclusão da tarefa assíncrona
Utilizando supplyAsync

Aqui, usamos supplyAsync para iniciar uma tarefa que retorna um valor. Este método é ideal para operações que executam alguma lógica e retornam um resultado, sendo executado de maneira assíncrona no mesmo executor padrão.

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    return "Resultado de tarefa assíncrona com retorno";
});
var resultado = future.get();  // Aguarda e recupera o resultado
Combinando Tarefas com allOf

Este exemplo mostra como aguardar a conclusão de múltiplas CompletableFutures. O método allOf é utilizado para criar um novo CompletableFuture que é concluído quando todas as CompletableFutures fornecidas são concluídas. Quando todas tarefas serem completadas, o método thenRun é chamado.

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Tarefa 1 completa");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Tarefa 2 completa");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2)
    .thenRun(() -> System.out.println("Todas as tarefas completas"));

allFutures.join();  // Aguarda a conclusão de todas as tarefas
var valueFuture1 = future1.get(); // recupera o resultado do primeiro CompletableFuture
var valueFuture2 = future2.get(); // recupera o resultado do segundo CompletableFuture
Selecionando a Primeira Tarefa Completa com anyOf

O método anyOf é usado quando você precisa que qualquer uma das tarefas fornecidas complete primeiro. Ele retorna um CompletableFuture que é completado com o resultado da primeira CompletableFuture que completar entre as fornecidas.

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Tarefa 1 completa");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "Tarefa 2 completa");
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
anyFuture.thenAccept(System.out::println); // Imprime resultado do primeiro CompletableFuture a ser completado
var anyValue = (String) anyFuture.get(); // recupera o resultado do primeiro CompletableFuture a ser completado
Utilizando delayedExecutor para Execução Delayed

Este exemplo configura um executor com um delay especificado antes de executar uma tarefa. O método delayedExecutor cria um executor que inicia a tarefa após um período de tempo definido, aqui sendo 1 segundo.

Executor delayedExecutor = CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    System.out.println("Execução com delay de 1 segundo.");
}, delayedExecutor);
future.get();  // Aguarda a conclusão da tarefa com delay

Conclusão

CompletableFuture é muito útil e versátil para desenvolvimento Java, especialmente útil para aplicações que necessitam de alta performance e eficiência em processamento assíncrono. Ao incorporar CompletableFuture em seus projetos, você pode obter um controle muito maior sobre as operações assíncronas e seus fluxos de trabalho, além de melhorar significativamente a performance das suas aplicações.

// Compartilhe esse Post

💫
🔥 NOVO APP

Domine o Inglês em 30 dias!

Inteligência Artificial + Repetição Espaçada • Método cientificamente comprovado

✅ Grátis para começar 🚀 Resultados rápidos
×