L'API STREAM EN JAVA
Guide Complet pour Débutants
De A à Z - Expliqué Simplement
1. C'est Quoi un Stream ?
Imagine que tu as une boîte de bonbons de différentes couleurs. Tu veux faire
plusieurs choses avec ces bonbons :
• Compter combien il y en a
• Garder seulement les rouges
• Trier par taille
• Transformer chaque bonbon en sucette
Un Stream en Java, c'est comme un tapis roulant magique où tes bonbons passent
un par un, et à chaque étape, tu peux faire une action dessus.
Avant vs Après les Streams
AVANT (Boucle for) APRÈS (Stream)
List<Integer> result = new ArrayList<>(); List<Integer> result = numbers
for (Integer n : numbers) { .stream()
if (n > 5) { .filter(n -> n > 5)
[Link](n * 2); .map(n -> n * 2)
} .collect([Link]());
}
2. Comment Créer un Stream ?
Il y a plusieurs façons de créer un Stream. Voici les plus courantes :
Méthode 1 : À partir d'une Liste
// Créer une liste
List<String> fruits = [Link]("pomme", "banane", "orange");
// Créer un Stream à partir de la liste
Stream<String> streamFruits = [Link]();
Méthode 2 : Directement avec [Link]()
// Créer un Stream directement
Stream<String> stream = [Link]("un", "deux", "trois");
Méthode 3 : Stream de nombres
// Nombres de 1 à 10
IntStream nombres = [Link](1, 10);
// Nombres de 1 à 9 (10 exclu)
IntStream nombres2 = [Link](1, 10);
3. Les Opérations Intermédiaires
Ce sont les transformations qu'on applique sur le tapis roulant. Elles retournent
toujours un nouveau Stream.
3.1 filter() - Filtrer les éléments
Objectif : Garder seulement les éléments qui respectent une condition.
List<Integer> nombres = [Link](1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Garder seulement les nombres pairs
List<Integer> pairs = [Link]()
.filter(n -> n % 2 == 0) // n -> n % 2 == 0 est une "lambda"
.collect([Link]());
// Résultat : [2, 4, 6, 8, 10]
C'est quoi une Lambda ?
Une lambda c'est une mini-fonction écrite en raccourci :
n -> n % 2 == 0
Se lit : "pour chaque n, vérifie si n modulo 2 égale 0"
n = le paramètre (chaque élément du Stream)
-> = la flèche ("fait ceci")
n % 2 == 0 = le corps (ce qu'on fait)
3.2 map() - Transformer les éléments
Objectif : Transformer chaque élément en autre chose.
List<String> noms = [Link]("alice", "bob", "charlie");
// Transformer en MAJUSCULES
List<String> majuscules = [Link]()
.map(nom -> [Link]())
.collect([Link]());
// Résultat : ["ALICE", "BOB", "CHARLIE"]
// Obtenir la longueur de chaque nom
List<Integer> longueurs = [Link]()
.map(nom -> [Link]())
.collect([Link]());
// Résultat : [5, 3, 7]
3.3 sorted() - Trier les éléments
List<Integer> nombres = [Link](5, 2, 8, 1, 9, 3);
// Tri croissant (naturel)
List<Integer> triCroissant = [Link]()
.sorted()
.collect([Link]());
// Résultat : [1, 2, 3, 5, 8, 9]
// Tri décroissant
List<Integer> triDecroissant = [Link]()
.sorted([Link]())
.collect([Link]());
// Résultat : [9, 8, 5, 3, 2, 1]
3.4 distinct() - Supprimer les doublons
List<Integer> avecDoublons = [Link](1, 2, 2, 3, 3, 3, 4);
List<Integer> sansDoublons = [Link]()
.distinct()
.collect([Link]());
// Résultat : [1, 2, 3, 4]
3.5 limit() et skip() - Prendre ou Sauter
List<Integer> nombres = [Link](1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// Prendre les 3 premiers
List<Integer> premiers = [Link]()
.limit(3)
.collect([Link]()); // [1, 2, 3]
// Sauter les 5 premiers
List<Integer> apres5 = [Link]()
.skip(5)
.collect([Link]()); // [6, 7, 8, 9, 10]
4. Les Opérations Terminales
Ce sont les opérations qui terminent le Stream et produisent un résultat final. Après
une opération terminale, le Stream est fermé et ne peut plus être utilisé.
4.1 collect() - Récupérer dans une collection
// En Liste
List<String> liste = [Link]([Link]());
// En Set (sans doublons)
Set<String> set = [Link]([Link]());
// En Map
Map<String, Integer> map = [Link]()
.collect([Link](
p -> [Link](), // clé
p -> [Link]() // valeur
));
// Joindre en String
String resultat = [Link]()
.collect([Link](", "));
// "alice, bob, charlie"
4.2 forEach() - Exécuter une action
List<String> fruits = [Link]("pomme", "banane", "orange");
// Afficher chaque fruit
[Link]().forEach(fruit -> [Link](fruit));
// Ou encore plus court avec référence de méthode !
[Link]().forEach([Link]::println);
4.3 count(), min(), max() - Statistiques
List<Integer> nombres = [Link](5, 2, 8, 1, 9, 3);
// Compter
long count = [Link]().count(); // 6
// Minimum
Optional<Integer> min = [Link]().min(Integer::compareTo); // 1
// Maximum
Optional<Integer> max = [Link]().max(Integer::compareTo); // 9
4.4 findFirst() et findAny() - Trouver
List<String> noms = [Link]("Alice", "Bob", "Anna", "Adam");
// Trouver le premier nom qui commence par 'A'
Optional<String> premier = [Link]()
.filter(n -> [Link]("A"))
.findFirst();
// Résultat : Optional[Alice]
// Pour obtenir la valeur
String nom = [Link]("Pas trouvé"); // "Alice"
4.5 anyMatch(), allMatch(), noneMatch() - Vérifier
List<Integer> notes = [Link](15, 12, 18, 9, 14);
// Est-ce qu'AU MOINS UN a plus de 17 ?
boolean auMoinsUn = [Link]().anyMatch(n -> n > 17); // true
// Est-ce que TOUS ont plus de 10 ?
boolean tous = [Link]().allMatch(n -> n > 10); // false (9)
// Est-ce que AUCUN n'est négatif ?
boolean aucun = [Link]().noneMatch(n -> n < 0); // true
4.6 reduce() - Réduire à une seule valeur
Objectif : Combiner tous les éléments en un seul résultat.
List<Integer> nombres = [Link](1, 2, 3, 4, 5);
// Somme de tous les nombres
int somme = [Link]()
.reduce(0, (a, b) -> a + b);
// Résultat : 15
// Explication:
// 0 = valeur initiale
// a = accumulateur (résultat en cours)
// b = élément courant
// Produit de tous les nombres
int produit = [Link]()
.reduce(1, (a, b) -> a * b); // 120
5. Exemple Complet : Gestion
d'Employés
Voici un exemple réel avec une classe Employe :
class Employe {
String nom;
String departement;
double salaire;
// Constructeur, getters...
}
List<Employe> employes = [Link](
new Employe("Alice", "IT", 55000),
new Employe("Bob", "RH", 45000),
new Employe("Charlie", "IT", 60000),
new Employe("Diana", "Marketing", 50000),
new Employe("Eve", "IT", 52000)
);
// 1. Noms des employés IT gagnant plus de 50000
List<String> nomsIT = [Link]()
.filter(e -> [Link]().equals("IT"))
.filter(e -> [Link]() > 50000)
.map(Employe::getNom)
.collect([Link]());
// ["Alice", "Charlie", "Eve"]
// 2. Salaire moyen de tous les employés
double moyenne = [Link]()
.mapToDouble(Employe::getSalaire)
.average()
.orElse(0.0);
// 52400.0
// 3. Grouper par département
Map<String, List<Employe>> parDept = [Link]()
.collect([Link](Employe::getDepartement));
// {IT=[Alice, Charlie, Eve], RH=[Bob], Marketing=[Diana]}
// 4. L'employé le mieux payé
Optional<Employe> topSalaire = [Link]()
.max([Link](Employe::getSalaire));
// Optional[Charlie - 60000]
6. Les Pièges à Éviter
❌ Piège 1 : Réutiliser un Stream
// ❌ ERREUR : Un Stream ne peut être utilisé qu'UNE SEULE FOIS
Stream<String> stream = [Link]();
[Link]([Link]::println); // OK
[Link](); // 💥 IllegalStateException !
// ✅ CORRECT : Créer un nouveau Stream à chaque fois
[Link]().forEach([Link]::println);
[Link]().count();
❌ Piège 2 : Modifier la collection source
// ❌ DANGER : Ne jamais modifier la liste pendant le Stream
List<String> liste = new ArrayList<>([Link]("a", "b", "c"));
[Link]().forEach(s -> [Link]("x")); //
ConcurrentModificationException
❌ Piège 3 : Oublier l'opération terminale
// ❌ ERREUR : Le Stream ne fait RIEN sans opération terminale !
[Link]()
.filter(n -> n > 5)
.map(n -> n * 2); // Rien ne se passe ! (Lazy evaluation)
// ✅ CORRECT : Ajouter une opération terminale
List<Integer> resultat = [Link]()
.filter(n -> n > 5)
.map(n -> n * 2)
.collect([Link]()); // Maintenant ça marche !
7. Résumé : Mémo Rapide
Opération Type Ce que ça fait
filter() Intermédiaire Garde si condition vraie
map() Intermédiaire Transforme chaque élément
sorted() Intermédiaire Trie les éléments
distinct() Intermédiaire Enlève les doublons
limit(n) Intermédiaire Garde les n premiers
skip(n) Intermédiaire Saute les n premiers
collect() Terminale Récupère en collection
forEach() Terminale Exécute une action
count() Terminale Compte les éléments
reduce() Terminale Combine en une valeur
findFirst() Terminale Trouve le premier
anyMatch() Terminale Au moins un match ?
🎉 Félicitations !
Tu connais maintenant les bases de l'API Stream en Java !
La clé : Pratique, pratique, pratique !