Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre Performance dans l'API Stream | Applications Pratiques de l'API Stream
API Stream

bookPerformance dans l'API Stream

Vous avez réussi à refactoriser le code, le rendant plus propre, plus court et plus expressif. Mais qu'en est-il de la performance ? Quelle est l’efficacité de l’API Stream par rapport aux boucles traditionnelles ? Est-il possible d’accélérer le traitement avec parallelStream() ? Découvrons-le !

Mesure du temps d’exécution

Pour comparer objectivement la performance, un jeu de données de test de 100 000 utilisateurs avec différentes commandes sera créé. Trois méthodes de filtrage seront ensuite implémentées :

  • for-loop traditionnel – approche classique avec boucles imbriquées ;
  • API Stream (stream()) – méthode déclarative moderne ;
  • API Stream parallèle (parallelStream()) – traitement multithread.

Le temps d’exécution sera mesuré à l’aide de System.nanoTime(), qui fournit des différences de temps de haute précision.

Implémentation du test

Générez 100 000 utilisateurs, en veillant à ce qu’ils aient tous des commandes supérieures à 10 000 $, puis exécutez les trois méthodes afin de déterminer laquelle offre les meilleures performances.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = generateUsers(100000); // Measuring traditional loop execution time long startTime = System.nanoTime(); List<User> premiumUsersLoop = new ArrayList<>(); for (User user : users) { if (user.isActive()) { int totalOrders = 0; for (Order order : user.getOrders()) { if (order.getTotal() >= 10000) { totalOrders++; } } if (totalOrders >= 3) { premiumUsersLoop.add(user); } } } long endTime = System.nanoTime(); System.out.println("For-loop: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersStream = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Parallel Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersParallelStream = users.parallelStream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Parallel Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); } private static List<User> generateUsers(int count) { List<User> users = new ArrayList<>(); for (int i = 0; i < count; i++) { users.add(new User("User" + i, true, List.of( new Order(14000), new Order(5000), new Order(7000) ))); } return users; } } class Order { private final double total; public Order(double total) { this.total = total; } public double getTotal() { return total; } } class User { private final String name; private final boolean active; private final List<Order> orders; public User(String name, boolean active, List<Order> orders) { this.name = name; this.active = active; this.orders = orders; } public boolean isActive() { return active; } public List<Order> getOrders() { return orders; } @Override public String toString() { return "User{name='" + name + "'}"; } }

Après avoir exécuté le test avec 100 000 utilisateurs, les tendances suivantes peuvent être observées :

La boucle traditionnelle for-loop est plus rapide pour les opérations simples car elle évite la surcharge liée à la création de flux et d’objets supplémentaires. Elle offre les meilleures performances lorsque la vitesse brute est prioritaire.

L’API Stream est parfois légèrement plus lente en raison des objets de flux supplémentaires, mais elle améliore considérablement la lisibilité et la maintenabilité du code.

L’API Parallel Stream peut accélérer le traitement sur les systèmes multi-cœurs, mais pas toujours. Si le jeu de données est petit, la gestion des threads peut en réalité ralentir le processus. Elle est plus efficace pour les calculs intensifs, mais pas lors de la modification de variables partagées, car les threads s’exécutent indépendamment.

Résumé

L'API Stream est un outil puissant qui rend le code plus lisible et concise. Cependant, en ce qui concerne la performance, il est important de comprendre ses limites. Dans certains cas, les boucles for traditionnelles sont plus rapides, en particulier lors du traitement de petits ensembles de données. parallelStream() peut améliorer la vitesse de traitement, mais il nécessite des tests pour s'assurer qu'il apporte réellement un avantage.

Ainsi, le choix de la bonne approche doit être intentionnel : si la lisibilité est prioritaire, utiliser l'API Stream ; si la performance est essentielle, tester et mesurer !

1. Quelle approche est généralement la plus rapide pour des opérations simples ?

2. Pourquoi l'API Stream peut-elle être plus lente qu'une boucle classique ?

3. Quand parallelStream() peut-il ralentir l'exécution ?

question mark

Quelle approche est généralement la plus rapide pour des opérations simples ?

Select the correct answer

question mark

Pourquoi l'API Stream peut-elle être plus lente qu'une boucle classique ?

Select the correct answer

question mark

Quand parallelStream() peut-il ralentir l'exécution ?

Select the correct answer

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 4. Chapitre 2

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

Awesome!

Completion rate improved to 2.33

bookPerformance dans l'API Stream

Glissez pour afficher le menu

Vous avez réussi à refactoriser le code, le rendant plus propre, plus court et plus expressif. Mais qu'en est-il de la performance ? Quelle est l’efficacité de l’API Stream par rapport aux boucles traditionnelles ? Est-il possible d’accélérer le traitement avec parallelStream() ? Découvrons-le !

Mesure du temps d’exécution

Pour comparer objectivement la performance, un jeu de données de test de 100 000 utilisateurs avec différentes commandes sera créé. Trois méthodes de filtrage seront ensuite implémentées :

  • for-loop traditionnel – approche classique avec boucles imbriquées ;
  • API Stream (stream()) – méthode déclarative moderne ;
  • API Stream parallèle (parallelStream()) – traitement multithread.

Le temps d’exécution sera mesuré à l’aide de System.nanoTime(), qui fournit des différences de temps de haute précision.

Implémentation du test

Générez 100 000 utilisateurs, en veillant à ce qu’ils aient tous des commandes supérieures à 10 000 $, puis exécutez les trois méthodes afin de déterminer laquelle offre les meilleures performances.

Main.java

Main.java

copy
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
package com.example; import java.util.ArrayList; import java.util.List; public class Main { public static void main(String[] args) { List<User> users = generateUsers(100000); // Measuring traditional loop execution time long startTime = System.nanoTime(); List<User> premiumUsersLoop = new ArrayList<>(); for (User user : users) { if (user.isActive()) { int totalOrders = 0; for (Order order : user.getOrders()) { if (order.getTotal() >= 10000) { totalOrders++; } } if (totalOrders >= 3) { premiumUsersLoop.add(user); } } } long endTime = System.nanoTime(); System.out.println("For-loop: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersStream = users.stream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); // Measuring Parallel Stream API execution time startTime = System.nanoTime(); List<User> premiumUsersParallelStream = users.parallelStream() .filter(User::isActive) .filter(user -> user.getOrders().stream() .filter(order -> order.getTotal() >= 10000) .count() >= 3) .toList(); endTime = System.nanoTime(); System.out.println("Parallel Stream API: " + (endTime - startTime) / 1_000_000 + " ms"); } private static List<User> generateUsers(int count) { List<User> users = new ArrayList<>(); for (int i = 0; i < count; i++) { users.add(new User("User" + i, true, List.of( new Order(14000), new Order(5000), new Order(7000) ))); } return users; } } class Order { private final double total; public Order(double total) { this.total = total; } public double getTotal() { return total; } } class User { private final String name; private final boolean active; private final List<Order> orders; public User(String name, boolean active, List<Order> orders) { this.name = name; this.active = active; this.orders = orders; } public boolean isActive() { return active; } public List<Order> getOrders() { return orders; } @Override public String toString() { return "User{name='" + name + "'}"; } }

Après avoir exécuté le test avec 100 000 utilisateurs, les tendances suivantes peuvent être observées :

La boucle traditionnelle for-loop est plus rapide pour les opérations simples car elle évite la surcharge liée à la création de flux et d’objets supplémentaires. Elle offre les meilleures performances lorsque la vitesse brute est prioritaire.

L’API Stream est parfois légèrement plus lente en raison des objets de flux supplémentaires, mais elle améliore considérablement la lisibilité et la maintenabilité du code.

L’API Parallel Stream peut accélérer le traitement sur les systèmes multi-cœurs, mais pas toujours. Si le jeu de données est petit, la gestion des threads peut en réalité ralentir le processus. Elle est plus efficace pour les calculs intensifs, mais pas lors de la modification de variables partagées, car les threads s’exécutent indépendamment.

Résumé

L'API Stream est un outil puissant qui rend le code plus lisible et concise. Cependant, en ce qui concerne la performance, il est important de comprendre ses limites. Dans certains cas, les boucles for traditionnelles sont plus rapides, en particulier lors du traitement de petits ensembles de données. parallelStream() peut améliorer la vitesse de traitement, mais il nécessite des tests pour s'assurer qu'il apporte réellement un avantage.

Ainsi, le choix de la bonne approche doit être intentionnel : si la lisibilité est prioritaire, utiliser l'API Stream ; si la performance est essentielle, tester et mesurer !

1. Quelle approche est généralement la plus rapide pour des opérations simples ?

2. Pourquoi l'API Stream peut-elle être plus lente qu'une boucle classique ?

3. Quand parallelStream() peut-il ralentir l'exécution ?

question mark

Quelle approche est généralement la plus rapide pour des opérations simples ?

Select the correct answer

question mark

Pourquoi l'API Stream peut-elle être plus lente qu'une boucle classique ?

Select the correct answer

question mark

Quand parallelStream() peut-il ralentir l'exécution ?

Select the correct answer

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 4. Chapitre 2
some-alt