Como usar CompletableFuture para programação assíncrona?
O CompletableFuture
é uma API do Java 8 que facilita a execução de tarefas assíncronas, permitindo processamento paralelo, encadeamento de operações e tratamento de exceções sem bloquear a thread principal.
1. Criando um CompletableFuture
básico
import java.util.concurrent.CompletableFuture;
public class Exemplo {
public static void main(String[] args) {
CompletableFuture<String> futuro = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(2000); } catch (InterruptedException e) {}
return "Resultado da tarefa assíncrona";
});
futuro.thenAccept(resultado -> System.out.println("Finalizado: " + resultado));
System.out.println("Processo assíncrono iniciado...");
}
}
Explicação:
supplyAsync()
executa a tarefa em uma thread separada.thenAccept()
define uma ação que será executada quando a tarefa terminar.- O programa continua rodando sem esperar a execução do
CompletableFuture
.
2. Encadeando tarefas com thenApply()
Podemos processar o resultado antes de exibi-lo:
CompletableFuture.supplyAsync(() -> "Java")
.thenApply(resultado -> resultado + " Assíncrono")
.thenAccept(System.out::println);
Saída:
Java Assíncrono
3. Combinando múltiplas tarefas
Podemos executar duas operações em paralelo e combinar os resultados:
CompletableFuture<String> futuro1 = CompletableFuture.supplyAsync(() -> "Primeira tarefa");
CompletableFuture<String> futuro2 = CompletableFuture.supplyAsync(() -> "Segunda tarefa");
futuro1.thenCombine(futuro2, (resultado1, resultado2) -> resultado1 + " e " + resultado2)
.thenAccept(System.out::println);
Saída:
Primeira tarefa e Segunda tarefa
4. Tratamento de exceções com exceptionally()
Se uma exceção ocorrer, podemos capturá-la e definir um valor alternativo:
CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) throw new RuntimeException("Erro inesperado");
return "Sucesso";
}).exceptionally(ex -> "Erro tratado: " + ex.getMessage())
.thenAccept(System.out::println);
5. Esperando múltiplas tarefas terminarem
O método allOf()
espera que todas as tarefas sejam concluídas antes de prosseguir:
CompletableFuture<Void> todas = CompletableFuture.allOf(
CompletableFuture.runAsync(() -> System.out.println("Tarefa 1")),
CompletableFuture.runAsync(() -> System.out.println("Tarefa 2")),
CompletableFuture.runAsync(() -> System.out.println("Tarefa 3"))
);
todas.join(); // Aguarda todas finalizarem
Conclusão
O CompletableFuture
facilita a programação assíncrona, melhorando a eficiência e o desempenho de aplicações que lidam com múltiplas tarefas simultaneamente. Ele permite composição de chamadas assíncronas, tratamento de erros e execução paralela sem bloquear a thread principal.
Por que usar CompletableFuture para melhorar a concorrência em Java?
Em aplicações modernas, a execução assíncrona é essencial para melhorar o desempenho, especialmente em chamadas de API, consultas a banco de dados e processamento de grandes volumes de dados. O CompletableFuture
fornece uma maneira eficiente de trabalhar com operações não bloqueantes, permitindo que a aplicação continue responsiva enquanto realiza tarefas complexas.
Algumas aplicações:
- Processamento paralelo de tarefas demoradas
- Execução assíncrona de chamadas de API
- Consulta simultânea a múltiplas fontes de dados
- Melhoria da responsividade em aplicações web
Dicas para quem está começando
- Use
supplyAsync()
para retornar valores assíncronos - Encadeie chamadas com
thenApply()
para transformar resultados - Trate exceções com
exceptionally()
para evitar falhas - Use
allOf()
para esperar múltiplas tarefas terminarem
Contribuições de Rodrigo Farias