Programação Assíncrona
Foto de Luis P.
Por: Luis P.
15 de Janeiro de 2025

Programação Assíncrona

CompletableFuture no Java

Java CompletableFuture

A programação assíncrona é uma abordagem poderosa para melhorar a performance de aplicações que executam tarefas demoradas ou dependem de operações externas, como chamadas a APIs ou acesso a bancos de dados. No Java, a classe CompletableFuture, introduzida no Java 8, oferece um modelo funcional para trabalhar com operações assíncronas e pipelines de tarefas.

Neste artigo, exploraremos como usar o CompletableFuture para criar e gerenciar fluxos de execução assíncronos, além de destacar boas práticas para evitar problemas comuns.


O Que é o CompletableFuture?

O CompletableFuture é uma implementação da interface Future que permite:

  1. Executar tarefas de forma assíncrona.
  2. Encadear múltiplas tarefas em pipelines.
  3. Combinar os resultados de múltiplas operações.
  4. Manipular exceções de maneira funcional.

Criando um CompletableFuture

1. Operações Assíncronas Básicas

Você pode iniciar uma tarefa assíncrona usando o método runAsync ou supplyAsync:

Exemplo com runAsync:

import java.util.concurrent.CompletableFuture;

public class ExemploRunAsync {
    public static void main(String[] args) {
        CompletableFuture.runAsync(() -> {
            System.out.println("Executando tarefa assíncrona...");
        });
    }
}

Exemplo com supplyAsync:

import java.util.concurrent.CompletableFuture;

public class ExemploSupplyAsync {
    public static void main(String[] args) {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            return "Resultado da tarefa assíncrona";
        });

        future.thenAccept(System.out::println);
    }
}

Encadeamento de Tarefas

1. Usando thenApply

Transforme o resultado de uma tarefa para criar uma nova tarefa:

Exemplo:

CompletableFuture.supplyAsync(() -> "Java")
    .thenApply(s -> s + " é incrível!")
    .thenAccept(System.out::println);

2. Usando thenCompose

Encadeia duas tarefas dependentes, criando um pipeline de execução.

Exemplo:

CompletableFuture.supplyAsync(() -> "Tarefa 1")
    .thenCompose(resultado -> CompletableFuture.supplyAsync(() -> resultado + " + Tarefa 2"))
    .thenAccept(System.out::println);

3. Usando thenCombine

Combina os resultados de duas tarefas independentes.

Exemplo:

CompletableFuture<Integer> tarefa1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> tarefa2 = CompletableFuture.supplyAsync(() -> 20);

CompletableFuture<Integer> resultado = tarefa1.thenCombine(tarefa2, Integer::sum);

resultado.thenAccept(System.out::println); // Saída: 30

Tratamento de Exceções

O CompletableFuture permite manipular exceções de forma declarativa com métodos como exceptionally e handle.

1. Usando exceptionally

Retorna um valor padrão quando ocorre uma exceção:

Exemplo:

CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException("Erro na tarefa!");
})
.exceptionally(ex -> "Valor padrão")
.thenAccept(System.out::println);

2. Usando handle

Permite tratar o resultado da tarefa e a exceção no mesmo método.

Exemplo:

CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException("Erro na tarefa!");
})
.handle((resultado, ex) -> {
    if (ex != null) {
        return "Erro tratado: " + ex.getMessage();
    }
    return resultado;
})
.thenAccept(System.out::println);

Combinando Múltiplas Tarefas

1. Usando allOf

Espera todas as tarefas terminarem:

Exemplo:

CompletableFuture<Void> todas = CompletableFuture.allOf(
    CompletableFuture.runAsync(() -> System.out.println("Tarefa 1")),
    CompletableFuture.runAsync(() -> System.out.println("Tarefa 2"))
);

todas.join();

2. Usando anyOf

Retorna quando qualquer uma das tarefas termina:

Exemplo:

CompletableFuture<Object> qualquer = CompletableFuture.anyOf(
    CompletableFuture.supplyAsync(() -> "Resultado 1"),
    CompletableFuture.supplyAsync(() -> "Resultado 2")
);

qualquer.thenAccept(System.out::println);

Boas Práticas ao Usar CompletableFuture

  1. Evite Bloqueios Explícitos: Prefira thenApply, thenAccept ou join em vez de usar get para evitar bloqueios desnecessários.
  2. Use Pools de Threads Adequados: Especifique um Executor personalizado para evitar sobrecarga no pool padrão do ForkJoinPool.
  3. Trate Exceções Explicitamente: Sempre forneça mecanismos de fallback ou tratamento de erros.
  4. Evite Pipelines Muito Longos: Divida tarefas complexas em subcomponentes para facilitar a leitura e manutenção.

O CompletableFuture é uma ferramenta poderosa para lidar com operações assíncronas e fluxos complexos de tarefas no Java. Com ele, você pode criar pipelines de execução flexíveis, combinar resultados de tarefas independentes e lidar com erros de forma eficiente. Adotar boas práticas e explorar seus recursos avançados pode melhorar significativamente a performance e a legibilidade do seu código. Experimente o CompletableFuture em seus projetos e aproveite suas vantagens no desenvolvimento moderno!

Luis P.
Luis P.
Boa Ventura / PB
Responde em 1 dia
Identidade verificada
1ª hora grátis
5,0
nota média
1
avaliação
R$ 40
por hora
Graduação: Licenciatura em Computação (UEPB - Universidade Estadual da Paraíba)
Testes em Java, Java - Springboot, Java para Web
Professor de informática, português e inglês. Formado em computação e letras inglês/português. Servidor público aprovado em 3 concursos.

Resolva exercícios e atividades acadêmicas

Resolução de exercícios, atividades acadêmicas, lição de casa, listas de exercícios, tarefas, revisão de textos e muito mais.

Professores especialistas para resolver passo a passo, dentro do seu prazo!

Tarefas Profes

Artigos similares

Tutoria com Inteligência Artificial

Conheça a Minerva IA e aprenda Java, tire dúvidas e resolva exercícios. Personalizado e no seu ritmo.

Tecnologia do ChatGPT. Use texto, áudio, fotos, imagens e arquivos.

Minerva IA