CompletableFuture
Falta apenas um último passo! Neste capítulo, será apresentada a principal classe de assincronia CompletableFuture.
Vamos utilizar uma analogia do cotidiano. Você chama um táxi por meio de um aplicativo (criação da tarefa). Enquanto aguarda, o aplicativo pode fornecer atualizações sobre a localização do carro ou o tempo estimado de chegada (processamento do resultado). Caso ocorram problemas como atrasos ou cancelamentos, o aplicativo irá notificar e sugerir alternativas (tratamento de exceções).
Principais Métodos
A primeira dúvida pode ser como iniciar uma tarefa utilizando CompletableFuture. Para isso, utiliza-se o método supplyAsync(), projetado para executar uma tarefa que retorna o resultado de forma assíncrona.
Main.java
12345678910// Creating an asynchronous task CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return "Result"; // Result }); // Processing the result after the task completes future.thenAccept(result -> { // Print the result to the console System.out.println("Result received: " + result); // Result received: });
Também existe o método thenAccept(), que lida com o valor retornado de um CompletableFuture em código assíncrono. Ele não retorna nada; é útil quando é necessário aceitar uma resposta e processá-la de alguma forma.
No exemplo, a tarefa é executada assíncronamente, e future.thenAccept() recebe a resposta da lambda, que pode então ser utilizada para impressão no console.
Existe um método semelhante, thenApply(), que funciona como o thenAccept(), mas obtém o resultado da tarefa assíncrona e retorna um novo resultado.
Main.java
12345678910// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Transforming the result to uppercase CompletableFuture<String> transformedFuture = future.thenApply(result -> result.toUpperCase()); // Printing the transformed result to the console transformedFuture.thenAccept(result -> { System.out.println("Transformed result: " + result); // Transformed result: });
E se não quisermos obter o resultado da tarefa assíncrona, mas apenas ser notificados quando ela for concluída?
Para isso, podemos usar o thenRun(), que é executado após a conclusão da tarefa assíncrona.
Main.java
12345678// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Running a task when the previous task completes future.thenRun(() -> { // Print message to the console indicating that the task is complete System.out.println("Task completed!"); // Task completed! });
Também é possível recuperar o resultado de uma tarefa assíncrona bloqueando a thread atual até que a tarefa seja concluída. Para isso, utiliza-se o método get().
Main.java
1234567CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
Existe também o método join(), que também pausa a thread atual e aguarda a conclusão da tarefa assíncrona. No entanto, a diferença entre join() e get() é que eles lançam exceções diferentes.
Main.java
12345// Create a `CompletableFuture` that asynchronously executes a task and returns the string "Hello World". CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); // The `join()` method blocks the current thread until the task is completed and returns the result "Hello World". String result = completableFuture.join();
Aqui não tratamos a exceção porque o método join() lança uma CompletionException não verificada.
Combinando Tarefas e Encadeando-as
É possível combinar tarefas em CompletableFuture utilizando o método thenCompose(), que permite unir duas tarefas dependentes.
Main.java
12345678910111213141516171819202122232425// Method to get book details from a remote service public CompletableFuture<String> getBookDetails() { return CompletableFuture.supplyAsync(() -> { // Request to a remote service to get book details return "Book Details"; // Placeholder for book details }); } // Method to get author details from a remote service public CompletableFuture<String> getAuthorDetails(String bookDetails) { return CompletableFuture.supplyAsync(() -> { // Request to another service to get author details return bookDetails + " Author"; // Placeholder for author details }); } // Combine two asynchronous tasks: get book details and then get author details CompletableFuture<String> result = getBookDetails() .thenCompose(book -> getAuthorDetails(book)); // Process the result and print the author details to the console result.thenAccept(author -> { // Print the author details to the console System.out.println("Author: " + author); // Author details });
Primeiro, os dados do livro são obtidos assincronamente utilizando o método getBookDetails(), e então o resultado é utilizado para executar a próxima tarefa assíncrona—buscar os dados do autor por meio do método getAuthorDetails(). Após a conclusão de ambas as tarefas, o resultado (informações do autor) é exibido no console.
Também é possível mesclar os resultados de duas tarefas utilizando o método thenCombine(). Ele executa ambas as tarefas concorrentemente e combina seus resultados assim que ambas estiverem concluídas.
Main.java
123456789101112// CompletableFuture for adding two numbers CompletableFuture<Double> firstNumberFuture = CompletableFuture.supplyAsync(() -> 50.0); CompletableFuture<Double> secondNumberFuture = CompletableFuture.supplyAsync(() -> 30.0); // Combine the two futures by adding their results CompletableFuture<Double> sumFuture = firstNumberFuture.thenCombine(secondNumberFuture, (first, second) -> first + second); // Print the result of the addition to the console sumFuture.thenAccept(sum -> { System.out.println("Sum: " + sum); // Sum: 80.0 });
Este código recupera de forma assíncrona dois números, soma-os e imprime o resultado no console.
Também é possível aguardar a conclusão de todas as tarefas utilizando o método allOf(), ou de qualquer uma delas utilizando o método anyOf().
Main.java
1234567891011121314151617181920CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { // Task 1 System.out.println("Task 1 completed"); }); CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> { // Task 2 System.out.println("Task 2 completed"); }); // Combine both futures and wait for both tasks to complete CompletableFuture<Void> combinedFuture1 = CompletableFuture.allOf(future1, future2); // Combine both futures and proceed as soon as any one task completes CompletableFuture<Object> combinedFuture2 = CompletableFuture.anyOf(future1, future2); // Print a message after all tasks are completed combinedFuture1.thenRun(() -> { System.out.println("All tasks completed"); });
Como lidar com erros e o que é um timeout?
Trecho curto do vídeo
handle(): Processa o resultado ou trata quaisquer exceções lançadas peloCompletableFuture;exceptionally(): Trata exceções lançadas durante a execução doCompletableFuture;completeOnTimeout(): Conclui oCompletableFuturecom um valor especificado caso ocorra timeout antes da conclusão.
CompletableFuture facilita o gerenciamento de tarefas assíncronas e o processamento de seus resultados, tornando-se uma ferramenta poderosa para o desenvolvimento de aplicações modernas.
Obrigado pelo seu feedback!
Pergunte à IA
Pergunte à IA
Pergunte o que quiser ou experimente uma das perguntas sugeridas para iniciar nosso bate-papo
What are some practical examples of using CompletableFuture in real applications?
Can you explain the difference between thenAccept(), thenApply(), and thenRun()?
How do you handle exceptions when working with CompletableFuture?
Incrível!
Completion taxa melhorada para 3.33
CompletableFuture
Deslize para mostrar o menu
Falta apenas um último passo! Neste capítulo, será apresentada a principal classe de assincronia CompletableFuture.
Vamos utilizar uma analogia do cotidiano. Você chama um táxi por meio de um aplicativo (criação da tarefa). Enquanto aguarda, o aplicativo pode fornecer atualizações sobre a localização do carro ou o tempo estimado de chegada (processamento do resultado). Caso ocorram problemas como atrasos ou cancelamentos, o aplicativo irá notificar e sugerir alternativas (tratamento de exceções).
Principais Métodos
A primeira dúvida pode ser como iniciar uma tarefa utilizando CompletableFuture. Para isso, utiliza-se o método supplyAsync(), projetado para executar uma tarefa que retorna o resultado de forma assíncrona.
Main.java
12345678910// Creating an asynchronous task CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { return "Result"; // Result }); // Processing the result after the task completes future.thenAccept(result -> { // Print the result to the console System.out.println("Result received: " + result); // Result received: });
Também existe o método thenAccept(), que lida com o valor retornado de um CompletableFuture em código assíncrono. Ele não retorna nada; é útil quando é necessário aceitar uma resposta e processá-la de alguma forma.
No exemplo, a tarefa é executada assíncronamente, e future.thenAccept() recebe a resposta da lambda, que pode então ser utilizada para impressão no console.
Existe um método semelhante, thenApply(), que funciona como o thenAccept(), mas obtém o resultado da tarefa assíncrona e retorna um novo resultado.
Main.java
12345678910// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Transforming the result to uppercase CompletableFuture<String> transformedFuture = future.thenApply(result -> result.toUpperCase()); // Printing the transformed result to the console transformedFuture.thenAccept(result -> { System.out.println("Transformed result: " + result); // Transformed result: });
E se não quisermos obter o resultado da tarefa assíncrona, mas apenas ser notificados quando ela for concluída?
Para isso, podemos usar o thenRun(), que é executado após a conclusão da tarefa assíncrona.
Main.java
12345678// Creating an asynchronous task that returns "Hello, World!" CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Hello, World!"); // Running a task when the previous task completes future.thenRun(() -> { // Print message to the console indicating that the task is complete System.out.println("Task completed!"); // Task completed! });
Também é possível recuperar o resultado de uma tarefa assíncrona bloqueando a thread atual até que a tarefa seja concluída. Para isso, utiliza-se o método get().
Main.java
1234567CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }
Existe também o método join(), que também pausa a thread atual e aguarda a conclusão da tarefa assíncrona. No entanto, a diferença entre join() e get() é que eles lançam exceções diferentes.
Main.java
12345// Create a `CompletableFuture` that asynchronously executes a task and returns the string "Hello World". CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); // The `join()` method blocks the current thread until the task is completed and returns the result "Hello World". String result = completableFuture.join();
Aqui não tratamos a exceção porque o método join() lança uma CompletionException não verificada.
Combinando Tarefas e Encadeando-as
É possível combinar tarefas em CompletableFuture utilizando o método thenCompose(), que permite unir duas tarefas dependentes.
Main.java
12345678910111213141516171819202122232425// Method to get book details from a remote service public CompletableFuture<String> getBookDetails() { return CompletableFuture.supplyAsync(() -> { // Request to a remote service to get book details return "Book Details"; // Placeholder for book details }); } // Method to get author details from a remote service public CompletableFuture<String> getAuthorDetails(String bookDetails) { return CompletableFuture.supplyAsync(() -> { // Request to another service to get author details return bookDetails + " Author"; // Placeholder for author details }); } // Combine two asynchronous tasks: get book details and then get author details CompletableFuture<String> result = getBookDetails() .thenCompose(book -> getAuthorDetails(book)); // Process the result and print the author details to the console result.thenAccept(author -> { // Print the author details to the console System.out.println("Author: " + author); // Author details });
Primeiro, os dados do livro são obtidos assincronamente utilizando o método getBookDetails(), e então o resultado é utilizado para executar a próxima tarefa assíncrona—buscar os dados do autor por meio do método getAuthorDetails(). Após a conclusão de ambas as tarefas, o resultado (informações do autor) é exibido no console.
Também é possível mesclar os resultados de duas tarefas utilizando o método thenCombine(). Ele executa ambas as tarefas concorrentemente e combina seus resultados assim que ambas estiverem concluídas.
Main.java
123456789101112// CompletableFuture for adding two numbers CompletableFuture<Double> firstNumberFuture = CompletableFuture.supplyAsync(() -> 50.0); CompletableFuture<Double> secondNumberFuture = CompletableFuture.supplyAsync(() -> 30.0); // Combine the two futures by adding their results CompletableFuture<Double> sumFuture = firstNumberFuture.thenCombine(secondNumberFuture, (first, second) -> first + second); // Print the result of the addition to the console sumFuture.thenAccept(sum -> { System.out.println("Sum: " + sum); // Sum: 80.0 });
Este código recupera de forma assíncrona dois números, soma-os e imprime o resultado no console.
Também é possível aguardar a conclusão de todas as tarefas utilizando o método allOf(), ou de qualquer uma delas utilizando o método anyOf().
Main.java
1234567891011121314151617181920CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { // Task 1 System.out.println("Task 1 completed"); }); CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> { // Task 2 System.out.println("Task 2 completed"); }); // Combine both futures and wait for both tasks to complete CompletableFuture<Void> combinedFuture1 = CompletableFuture.allOf(future1, future2); // Combine both futures and proceed as soon as any one task completes CompletableFuture<Object> combinedFuture2 = CompletableFuture.anyOf(future1, future2); // Print a message after all tasks are completed combinedFuture1.thenRun(() -> { System.out.println("All tasks completed"); });
Como lidar com erros e o que é um timeout?
Trecho curto do vídeo
handle(): Processa o resultado ou trata quaisquer exceções lançadas peloCompletableFuture;exceptionally(): Trata exceções lançadas durante a execução doCompletableFuture;completeOnTimeout(): Conclui oCompletableFuturecom um valor especificado caso ocorra timeout antes da conclusão.
CompletableFuture facilita o gerenciamento de tarefas assíncronas e o processamento de seus resultados, tornando-se uma ferramenta poderosa para o desenvolvimento de aplicações modernas.
Obrigado pelo seu feedback!