Collections et Streams
Progression
#Collections, Streams et parallélisme
Cette partie du cours est ancrée dans des scénarios très concrets : analyser des logs, agréger des statistiques de commandes, traiter un pipeline d’événements. Avant de sortir les Streams, nous revenons sur les structures de base et leurs implications. Pourquoi un ArrayList
domine souvent une liste chaînée en pratique ? Dans quels cas LinkedHashMap
devient un allié précieux pour préserver l’ordre ? Comment éviter les pièges de ConcurrentHashMap
et de CopyOnWriteArrayList
lorsqu’on entre dans le domaine de la concurrence ?
Une fois ces choix explicités, nous décortiquons l’API Stream. Les étudiantes et étudiants apprennent à raisonner sur la paresse des flux, à composer les transformations (map
, filter
, flatMap
) et à choisir les collecteurs qui produisent une structure pertinente. Nous détaillons également ce que signifie la parallélisation d’un Stream, quand il est pertinent d’activer parallel()
et quels coûts surveiller.
1var topProduits = commandes.stream()2 .flatMap(c -> c.lignes().stream())3 .collect(groupingBy(LigneCommande::produit, summingInt(LigneCommande::quantite)))4 .entrySet().stream()5 .sorted(Map.Entry.<Produit, Integer>comparingByValue().reversed())6 .limit(10)7 .toList();
#Parallélisme structuré
Au-delà des Streams, Java propose toute une palette pour structurer le parallélisme. Nous passons en revue CompletableFuture
avec un atelier qui agrège des appels réseau simulés, puis nous montrons comment StructuredTaskScope
améliore la lisibilité du code concurrent en imposant une hiérarchie claire aux tâches. Les virtual threads issus du projet Loom offrent enfin un moyen simple d’augmenter la concurrence d’un service I/O bound sans faire exploser la complexité.
#Exercices
- Implémentez un pipeline de calcul de statistiques sur des logs JSON massifs.
- Transformez une API REST bloquante en version Loom.