Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre CompletableFuture | Meilleures Pratiques de la Programmation Multithread
Multithreading en Java

bookCompletableFuture

Il ne reste plus qu'une dernière étape ! Dans ce chapitre, nous allons examiner la principale classe d'asynchronisme CompletableFuture.

Utilisation d'une analogie de la vie réelle. Vous appelez un taxi via une application (création de tâche). Pendant l'attente, l'application peut fournir des mises à jour sur la position du véhicule ou l'heure d'arrivée estimée (traitement du résultat). En cas de problèmes tels que des retards ou des annulations, l'application vous informe et propose des alternatives (gestion des exceptions).

Méthodes principales

La première question que l'on peut se poser est comment démarrer une tâche avec CompletableFuture. Pour cela, il est possible d'utiliser la méthode supplyAsync(), conçue pour exécuter une tâche qui retourne le résultat de manière asynchrone.

Main.java

Main.java

copy
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: });

Nous disposons également de la méthode thenAccept(), qui gère la valeur renvoyée par CompletableFuture dans un code asynchrone. Elle ne retourne rien ; elle est utile lorsque vous devez accepter une réponse et la traiter d'une certaine manière.

Note
Remarque

Dans notre exemple, nous exécutons la tâche asynchrone, et future.thenAccept() reçoit la réponse du lambda, que nous pouvons ensuite utiliser pour afficher dans la console.

Il existe une méthode similaire, thenApply(), qui fonctionne comme thenAccept() mais reçoit le résultat de la tâche asynchrone et retourne un nouveau résultat.

Main.java

Main.java

copy
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: });

Que faire si l’on ne souhaite pas obtenir le résultat de la tâche asynchrone mais simplement être notifié lorsqu’elle est terminée ?

Pour cela, on peut utiliser thenRun(), qui s’exécute après la fin de la tâche asynchrone.

Main.java

Main.java

copy
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! });

Il est également possible de récupérer le résultat d'une tâche asynchrone en bloquant le thread actuel jusqu'à ce que la tâche soit terminée. À cet effet, la méthode get() est utilisée.

Main.java

Main.java

copy
1234567
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }

Il existe également une méthode join(), qui suspend également le thread actuel et attend la fin de la tâche asynchrone. Cependant, la différence entre join() et get() réside dans le fait qu'elles lèvent des exceptions différentes.

Main.java

Main.java

copy
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();

Nous ne gérons pas l'exception ici car la méthode join() lève une CompletionException non vérifiée.

Combinaison et chaînage des tâches

Il est possible de combiner des tâches dans CompletableFuture en utilisant thenCompose(), qui permet de combiner deux tâches dépendantes.

Main.java

Main.java

copy
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 });

La récupération des données du livre s'effectue d'abord de manière asynchrone via la méthode getBookDetails(), puis le résultat est utilisé pour exécuter la tâche asynchrone suivante : obtenir les données de l'auteur à l'aide de la méthode getAuthorDetails(). Une fois les deux tâches terminées, le résultat (informations sur l'auteur) est affiché dans la console.

Nous pouvons également fusionner les résultats de deux tâches en utilisant la méthode thenCombine(). Elle exécute les deux tâches simultanément et combine leurs résultats une fois que les deux tâches sont terminées.

Main.java

Main.java

copy
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 });

Ce code récupère de manière asynchrone deux nombres, les additionne et affiche le résultat dans la console.

Il est également possible d'attendre que toutes les tâches soient terminées en utilisant la méthode allOf(), ou qu'une seule d'entre elles avec la méthode anyOf().

Main.java

Main.java

copy
1234567891011121314151617181920
CompletableFuture<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"); });

Comment gérer les erreurs et qu'est-ce qu'un délai d'expiration ?

Court extrait de la vidéo

  • handle(): Traite le résultat ou gère les exceptions levées par le CompletableFuture ;
  • exceptionally(): Gère les exceptions levées lors de l'exécution du CompletableFuture ;
  • completeOnTimeout(): Termine le CompletableFuture avec une valeur spécifiée en cas de dépassement de délai avant la complétion.
Note
Remarque

CompletableFuture facilite la gestion des tâches asynchrones et le traitement de leurs résultats, ce qui en fait un outil puissant pour le développement d'applications modernes.

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 4. Chapitre 6

Demandez à l'IA

expand

Demandez à l'IA

ChatGPT

Posez n'importe quelle question ou essayez l'une des questions suggérées pour commencer notre discussion

Suggested prompts:

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?

Awesome!

Completion rate improved to 3.33

bookCompletableFuture

Glissez pour afficher le menu

Il ne reste plus qu'une dernière étape ! Dans ce chapitre, nous allons examiner la principale classe d'asynchronisme CompletableFuture.

Utilisation d'une analogie de la vie réelle. Vous appelez un taxi via une application (création de tâche). Pendant l'attente, l'application peut fournir des mises à jour sur la position du véhicule ou l'heure d'arrivée estimée (traitement du résultat). En cas de problèmes tels que des retards ou des annulations, l'application vous informe et propose des alternatives (gestion des exceptions).

Méthodes principales

La première question que l'on peut se poser est comment démarrer une tâche avec CompletableFuture. Pour cela, il est possible d'utiliser la méthode supplyAsync(), conçue pour exécuter une tâche qui retourne le résultat de manière asynchrone.

Main.java

Main.java

copy
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: });

Nous disposons également de la méthode thenAccept(), qui gère la valeur renvoyée par CompletableFuture dans un code asynchrone. Elle ne retourne rien ; elle est utile lorsque vous devez accepter une réponse et la traiter d'une certaine manière.

Note
Remarque

Dans notre exemple, nous exécutons la tâche asynchrone, et future.thenAccept() reçoit la réponse du lambda, que nous pouvons ensuite utiliser pour afficher dans la console.

Il existe une méthode similaire, thenApply(), qui fonctionne comme thenAccept() mais reçoit le résultat de la tâche asynchrone et retourne un nouveau résultat.

Main.java

Main.java

copy
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: });

Que faire si l’on ne souhaite pas obtenir le résultat de la tâche asynchrone mais simplement être notifié lorsqu’elle est terminée ?

Pour cela, on peut utiliser thenRun(), qui s’exécute après la fin de la tâche asynchrone.

Main.java

Main.java

copy
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! });

Il est également possible de récupérer le résultat d'une tâche asynchrone en bloquant le thread actuel jusqu'à ce que la tâche soit terminée. À cet effet, la méthode get() est utilisée.

Main.java

Main.java

copy
1234567
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello World"); try { String result = completableFuture.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); }

Il existe également une méthode join(), qui suspend également le thread actuel et attend la fin de la tâche asynchrone. Cependant, la différence entre join() et get() réside dans le fait qu'elles lèvent des exceptions différentes.

Main.java

Main.java

copy
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();

Nous ne gérons pas l'exception ici car la méthode join() lève une CompletionException non vérifiée.

Combinaison et chaînage des tâches

Il est possible de combiner des tâches dans CompletableFuture en utilisant thenCompose(), qui permet de combiner deux tâches dépendantes.

Main.java

Main.java

copy
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 });

La récupération des données du livre s'effectue d'abord de manière asynchrone via la méthode getBookDetails(), puis le résultat est utilisé pour exécuter la tâche asynchrone suivante : obtenir les données de l'auteur à l'aide de la méthode getAuthorDetails(). Une fois les deux tâches terminées, le résultat (informations sur l'auteur) est affiché dans la console.

Nous pouvons également fusionner les résultats de deux tâches en utilisant la méthode thenCombine(). Elle exécute les deux tâches simultanément et combine leurs résultats une fois que les deux tâches sont terminées.

Main.java

Main.java

copy
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 });

Ce code récupère de manière asynchrone deux nombres, les additionne et affiche le résultat dans la console.

Il est également possible d'attendre que toutes les tâches soient terminées en utilisant la méthode allOf(), ou qu'une seule d'entre elles avec la méthode anyOf().

Main.java

Main.java

copy
1234567891011121314151617181920
CompletableFuture<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"); });

Comment gérer les erreurs et qu'est-ce qu'un délai d'expiration ?

Court extrait de la vidéo

  • handle(): Traite le résultat ou gère les exceptions levées par le CompletableFuture ;
  • exceptionally(): Gère les exceptions levées lors de l'exécution du CompletableFuture ;
  • completeOnTimeout(): Termine le CompletableFuture avec une valeur spécifiée en cas de dépassement de délai avant la complétion.
Note
Remarque

CompletableFuture facilite la gestion des tâches asynchrones et le traitement de leurs résultats, ce qui en fait un outil puissant pour le développement d'applications modernes.

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 4. Chapitre 6
some-alt