L'API Stream
L'API Stream (Java 8+) permet de traiter des collections comme un pipeline de données : chaque opération transforme ou filtre les éléments sans jamais modifier la collection d'origine.
Notions théoriques
Qu'est-ce qu'un Stream ?
Un Stream est une séquence d'éléments qui supporte des opérations enchaînées. Il ne stocke pas de données — il les traverse.
List<Personnage> vivants = personnages.stream()
.filter(p -> p.estVivant())
.collect(Collectors.toList());
Un Stream ne modifie jamais la collection source. Il produit un nouveau résultat.
On obtient un Stream depuis une collection avec .stream(), ou un Stream parallèle avec .parallelStream().
Opérations intermédiaires (lazy)
Les opérations intermédiaires ne s'exécutent pas immédiatement — elles sont lazy : elles attendent qu'une opération terminale déclenche le pipeline.
| Opération | Signature | Rôle |
|---|---|---|
filter | filter(Predicate<T>) | Garder les éléments qui satisfont la condition |
map | map(Function<T, R>) | Transformer chaque élément |
sorted | sorted(Comparator<T>) | Trier les éléments |
distinct | distinct() | Supprimer les doublons |
limit | limit(long n) | Garder les n premiers éléments |
peek | peek(Consumer<T>) | Inspecter sans modifier (débogage) |
personnages.stream()
.filter(p -> p.getForce() > 50) // filtre
.map(p -> p.getNom()) // transformation
.sorted() // tri alphabétique
.distinct() // doublons supprimés
.limit(5) // 5 premiers
.peek(nom -> System.out.println("Vu : " + nom)) // inspection
.collect(Collectors.toList());
Opérations terminales
Une opération terminale déclenche le pipeline et produit un résultat. Il ne peut y en avoir qu'une seule par Stream.
| Opération | Rôle |
|---|---|
collect(Collectors.toList()) | Rassembler dans une List |
forEach(Consumer) | Parcourir chaque élément |
count() | Compter les éléments |
findFirst() | Retourner le premier → Optional<T> |
reduce(identité, BinaryOperator) | Agréger en une seule valeur |
// Compter les guerriers
long nbGuerriers = personnages.stream()
.filter(p -> p instanceof Guerrier)
.count();
// Trouver le premier vivant
Optional<Personnage> premier = personnages.stream()
.filter(Personnage::estVivant)
.findFirst();
// Somme des forces
int totalForce = personnages.stream()
.mapToInt(Personnage::getForce)
.sum();