Traitement des Éléments avec la Méthode forEach()
Vous connaissez déjà la méthode forEach() puisque vous l'avez utilisée en pratique pour afficher chaque élément d'une collection sur la console. Examinons-la de plus près et explorons ses implémentations.
Elle offre un moyen pratique de traiter les données selon un style fonctionnel. Cependant, il est important de noter que l'ordre de traitement dépend du type de flux et de la méthode utilisée.
Il existe deux implémentations de la méthode forEach() dans la Stream API. Examinons-les une par une.
Méthode forEach
Exécute une action sur chaque élément, mais l'ordre de traitement n'est pas garanti dans les flux parallèles.
void forEach(Consumer<? super T> action)
La méthode forEach() prend un Consumer<T> en argument—une interface fonctionnelle qui définit une opération pour chaque élément du flux. Elle est couramment utilisée pour la journalisation, l'affichage ou l'exécution d'effets de bord.
Exemple pratique
Dans une boutique en ligne, les utilisateurs doivent recevoir des notifications concernant des remises personnalisées. Comme l'ordre n'a pas d'importance, forEach() est utilisé avec un flux parallèle pour une exécution plus rapide.
Main.java
1234567891011121314151617181920212223package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }
Ce code simule l'envoi de courriels de réduction personnalisés aux clients. Comme parallelStream() est utilisé, les courriels sont envoyés dans un ordre aléatoire pour améliorer la rapidité. La méthode forEach() applique l'action donnée à chaque courriel.
Méthode forEachOrdered
Exécute une action tout en préservant l'ordre des éléments, même dans les flux parallèles.
void forEachOrdered(Consumer<? super T> action)
Comme forEach, cette méthode accepte également un Consumer<T>, mais elle garantit que les éléments sont traités dans le même ordre que celui du flux d'origine. Ceci est utile lorsque le maintien de la séquence est essentiel.
Exemple pratique
Considérer un système de paiement où chaque transaction doit être traitée dans l'ordre exact de son arrivée. Si les paiements sont traités dans un ordre différent, cela peut entraîner des erreurs, telles que des calculs de solde incorrects.
Main.java
123456789101112131415161718192021package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }
Ce code simule un système de traitement des paiements où les transactions doivent être traitées dans l'ordre d'arrivée. L'utilisation de parallelStream() améliore les performances, mais forEachOrdered() garantit que la séquence reste intacte.
Comparaison des performances : forEach() vs. forEachOrdered()
Évaluation de la rapidité d'exécution de forEach() par rapport à forEachOrdered() lors de l'utilisation de flux parallèles. Pour cela, création d'une liste de 10 millions d'éléments, traitement avec les deux méthodes en calculant la racine carrée de chaque nombre, puis enregistrement du temps d'exécution.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }
La méthode forEach() traite les éléments sans préserver l'ordre, permettant au flux de répartir librement les tâches entre les cœurs de processeur disponibles. Cela maximise les performances, car chaque thread peut sélectionner les éléments dans n'importe quel ordre et les traiter en parallèle sans restrictions.
La méthode forEachOrdered() préserve l'ordre d'origine des éléments, ce qui nécessite une synchronisation supplémentaire. Dans un flux parallèle, les éléments sont d'abord divisés en blocs pour le traitement, mais leurs résultats doivent ensuite être réassemblés dans le bon ordre avant d'être transmis à la méthode de traitement.
1. Quelle interface fonctionnelle la méthode forEach accepte-t-elle ?
2. Quelle sortie ce code peut-il produire ?
Merci pour vos commentaires !
Demandez à l'IA
Demandez à l'IA
Posez n'importe quelle question ou essayez l'une des questions suggérées pour commencer notre discussion
Awesome!
Completion rate improved to 2.33
Traitement des Éléments avec la Méthode forEach()
Glissez pour afficher le menu
Vous connaissez déjà la méthode forEach() puisque vous l'avez utilisée en pratique pour afficher chaque élément d'une collection sur la console. Examinons-la de plus près et explorons ses implémentations.
Elle offre un moyen pratique de traiter les données selon un style fonctionnel. Cependant, il est important de noter que l'ordre de traitement dépend du type de flux et de la méthode utilisée.
Il existe deux implémentations de la méthode forEach() dans la Stream API. Examinons-les une par une.
Méthode forEach
Exécute une action sur chaque élément, mais l'ordre de traitement n'est pas garanti dans les flux parallèles.
void forEach(Consumer<? super T> action)
La méthode forEach() prend un Consumer<T> en argument—une interface fonctionnelle qui définit une opération pour chaque élément du flux. Elle est couramment utilisée pour la journalisation, l'affichage ou l'exécution d'effets de bord.
Exemple pratique
Dans une boutique en ligne, les utilisateurs doivent recevoir des notifications concernant des remises personnalisées. Comme l'ordre n'a pas d'importance, forEach() est utilisé avec un flux parallèle pour une exécution plus rapide.
Main.java
1234567891011121314151617181920212223package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> customers = List.of( "alice@example.com", "bob@example.com", "charlie@example.com" ); // Parallel stream for faster processing Stream<String> customerStream = customers.parallelStream(); customerStream.forEach(email -> sendDiscountEmail(email)); } private static void sendDiscountEmail(String email) { System.out.println("Sending discount email to: " + email); // Simulating email sending process } }
Ce code simule l'envoi de courriels de réduction personnalisés aux clients. Comme parallelStream() est utilisé, les courriels sont envoyés dans un ordre aléatoire pour améliorer la rapidité. La méthode forEach() applique l'action donnée à chaque courriel.
Méthode forEachOrdered
Exécute une action tout en préservant l'ordre des éléments, même dans les flux parallèles.
void forEachOrdered(Consumer<? super T> action)
Comme forEach, cette méthode accepte également un Consumer<T>, mais elle garantit que les éléments sont traités dans le même ordre que celui du flux d'origine. Ceci est utile lorsque le maintien de la séquence est essentiel.
Exemple pratique
Considérer un système de paiement où chaque transaction doit être traitée dans l'ordre exact de son arrivée. Si les paiements sont traités dans un ordre différent, cela peut entraîner des erreurs, telles que des calculs de solde incorrects.
Main.java
123456789101112131415161718192021package com.example; import java.util.List; import java.util.stream.Stream; public class Main { public static void main(String[] args) { List<String> payments = List.of( "Payment #5001 - $100", "Payment #5002 - $250", "Payment #5003 - $75" ); Stream<String> paymentStream = payments.parallelStream(); paymentStream.forEachOrdered(payment -> processPayment(payment)); } private static void processPayment(String payment) { System.out.println("Processing payment: " + payment); } }
Ce code simule un système de traitement des paiements où les transactions doivent être traitées dans l'ordre d'arrivée. L'utilisation de parallelStream() améliore les performances, mais forEachOrdered() garantit que la séquence reste intacte.
Comparaison des performances : forEach() vs. forEachOrdered()
Évaluation de la rapidité d'exécution de forEach() par rapport à forEachOrdered() lors de l'utilisation de flux parallèles. Pour cela, création d'une liste de 10 millions d'éléments, traitement avec les deux méthodes en calculant la racine carrée de chaque nombre, puis enregistrement du temps d'exécution.
Main.java
12345678910111213141516171819202122232425262728293031package com.example; import java.util.List; import java.util.stream.IntStream; import java.util.ArrayList; public class Main { public static void main(String[] args) { List<Integer> numbers = new ArrayList<>(); IntStream.range(0, 10_000_000).forEach(numbers::add); // Create a list with 10 million elements // Measure execution time of `forEach()` long startTime = System.nanoTime(); numbers.parallelStream().forEach(num -> process(num)); long forEachTime = System.nanoTime() - startTime; // Measure execution time of `forEachOrdered()` startTime = System.nanoTime(); numbers.parallelStream().forEachOrdered(num -> process(num)); long forEachOrderedTime = System.nanoTime() - startTime; // Print results System.out.println("forEach execution time: " + forEachTime / 1_000_000 + " ms"); System.out.println("forEachOrdered execution time: " + forEachOrderedTime / 1_000_000 + " ms"); } private static void process(int num) { // Simulate workload Math.sqrt(num); } }
La méthode forEach() traite les éléments sans préserver l'ordre, permettant au flux de répartir librement les tâches entre les cœurs de processeur disponibles. Cela maximise les performances, car chaque thread peut sélectionner les éléments dans n'importe quel ordre et les traiter en parallèle sans restrictions.
La méthode forEachOrdered() préserve l'ordre d'origine des éléments, ce qui nécessite une synchronisation supplémentaire. Dans un flux parallèle, les éléments sont d'abord divisés en blocs pour le traitement, mais leurs résultats doivent ensuite être réassemblés dans le bon ordre avant d'être transmis à la méthode de traitement.
1. Quelle interface fonctionnelle la méthode forEach accepte-t-elle ?
2. Quelle sortie ce code peut-il produire ?
Merci pour vos commentaires !