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
Awesome!
Completion rate improved to 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!