# 520 Exercices Java Complets - De Débutant à Expert

Guide d'utilisation :
- Chaque chapitre contient 10 exercices progressifs
- Les exercices explorent toutes les fonctionnalités du sujet traité
- Faites les exercices dans l'ordre pour une progression optimale
- N'hésitez pas à compiler et tester votre code

---

## [DOCS] SOMMAIRE COMPLET

### PARTIE 1 — Fondamentaux Java (Débutant)
1. Introduction à Java
2. Variables, types primitifs et opérations  
3. Chaînes de caractères (String)
4. Tableaux (Arrays)
5. Structures de contrôle
6. Méthodes (fonctions)
7. Introduction à la POO

### PARTIE 2 — POO Avancée et Collections  
8. Héritage
9. Classes abstraites et interfaces
10. Collections Framework - List
11. Collections Framework - Set et Map
12. Gestion des exceptions
13. Entrées/Sorties (I/O)
14. Génériques (Generics)

### PARTIE 3 — Java Moderne et Programmation Fonctionnelle
15. Lambda expressions et programmation fonctionnelle
16. Streams API
17. Optional
18. Date et Time API (java.time)
19. Annotations  
20. Enums

### PARTIE 4 — Java Entreprise et Frameworks
21. JDBC et Bases de Données
22. Servlets et JSP
23. Maven et Gestion de Dépendances
24. JUnit et Tests Unitaires
25. Logging

### PARTIE 5 — Frameworks et Technologies Avancées
26. Spring Core
27. Spring Boot
28. Spring Security
29. Hibernate et JPA
30. Microservices avec Spring Cloud

### PARTIE 6 — Programmation Avancée et Performance
31. Threads et Concurrence
32. Programmation réactive avec Reactor
33. Performance et Optimisation
34. Reflection et Introspection
35. Design Patterns

### PARTIE 7 — Clean Code et DevOps
36. Clean Code et SOLID
37. Sécurité en Java
38. Docker et Containerization
39. Kubernetes et Orchestration
40. CI/CD avec Jenkins et GitLab

### PARTIE 8 — Technologies Spécialisées
41. Kafka et Messaging
42. gRPC et Communication
43. GraphQL avec Java
44. Reactive Programming avec WebFlux
45. Native Cloud avec Quarkus
46. Serverless avec AWS Lambda
47. Machine Learning avec Java
48. Big Data avec Spark
49. Android Development
50. JavaFX pour Desktop
51. Performance Tuning Avancé
52. Devenir Expert Java

---

## [OBJECTIF] COMMENT UTILISER CE GUIDE

### Pour débutants absolus
Commencez au Chapitre 1 et progressez séquentiellement. Ne sautez pas de chapitres.

### Pour développeurs avec bases
Évaluez votre niveau et commencez au chapitre approprié. Les chapitres 1-7 sont les fondamentaux essentiels.

### Pour la préparation certification
Focus sur chapitres 1-20 pour Java SE, puis 21-30 pour Java EE.

### Pour spécialisation
Après maîtrise des fondamentaux (ch. 1-20), choisissez votre domaine :
- **Web/Enterprise** : ch. 21-30, 36-40
- **Microservices/Cloud** : ch. 30, 38-46
- **Performance** : ch. 31-35, 51
- **Mobile** : ch. 49
- **Desktop** : ch. 50

---

# 520 Exercices Java Complets - De Débutant à Expert

Guide d'utilisation :

- Chaque chapitre contient 10 exercices progressifs
- Les exercices explorent toutes les fonctionnalités du sujet traité
- Faites les exercices dans l'ordre pour une progression optimale
- N'hésitez pas à compiler et tester votre code

## [LIGHT_BLUE_HEART] PARTIE 1 — Les Fondamentaux (Débutant total)

---

### **Chapitre 1 — Introduction à Java**

**Exercice 1.1** - Premier contact  
Écris un programme Java avec une classe `HelloWorld` et une méthode `main` qui affiche "Bienvenue dans le monde de Java !" à l'écran. Utilise `System.out.println()`.

**Exercice 1.2** - Affichage multiple  
Crée un programme qui affiche 5 lignes différentes : ton prénom, ton âge, ta ville, ton pays et ta couleur préférée. Chaque information sur une ligne séparée.

**Exercice 1.3** - Commentaires  
Écris un programme qui affiche "Java est puissant" et ajoute au moins 3 types de commentaires : commentaire sur une ligne `//`, commentaire multi-lignes `/* */`, et commentaire Javadoc `/** */`.

**Exercice 1.4** - Affichage formaté  
Utilise `System.out.print()` (sans saut de ligne) et `System.out.println()` pour afficher plusieurs mots. Explore aussi `System.out.printf()` pour formater l'affichage.

**Exercice 1.5** - Concaténation de chaînes  
Écris un programme qui utilise l'opérateur `+` pour concaténer des chaînes. Affiche "Je", "code", "en Java" sur la même ligne avec des espaces entre chaque mot.

**Exercice 1.6** - Calculs simples  
Affiche directement le résultat de 15 + 27, 100 - 35, 12 * 8 et 144 / 12 avec `System.out.println()`. Affiche aussi le texte expliquant chaque opération.

**Exercice 1.7** - Caractères spéciaux  
Crée un programme qui affiche : une citation entre guillemets en utilisant `\"`, un texte avec un retour à la ligne `\n`, une tabulation `\t`, et un backslash `\\`.

**Exercice 1.8** - Répétition avec boucle simple  
Utilise une boucle `for` pour afficher 10 fois le symbole "*" sur la même ligne. Puis utilise une autre boucle pour afficher "Java" 5 fois verticalement.

**Exercice 1.9** - Affichage formaté simple  
Affiche un rectangle avec des caractères. Exemple :
```
****
*  *
****
```

**Exercice 1.10** - Programme interactif basique  
Écris un programme qui affiche "Appuie sur Entrée pour continuer...", attend que l'utilisateur appuie sur Entrée (utilise `Scanner` et `.nextLine()`), puis affiche "Programme terminé !".

---

### **Chapitre 2 — Variables, types primitifs et opérations**

**Exercice 2.1** - Déclaration de variables  
Crée 5 variables de types différents : `String nom`, `int age`, `double taille`, `boolean estEtudiant`, et `char initiale`. Initialise-les et affiche chaque variable avec son type.

**Exercice 2.2** - Opérations arithmétiques  
Crée deux variables `int a = 45` et `int b = 12`. Calcule et affiche : leur somme, différence, produit, division entière `/`, modulo `%`, et note la différence entre division entière et division avec doubles.

**Exercice 2.3** - Conversion de types (casting)  
Crée une variable `String nombreTexte = "123"`. Convertis-la en `int` avec `Integer.parseInt()`. Crée `double prix = 45.99` et convertis-la en `int` (casting). Affiche les résultats et observe la perte de précision.

**Exercice 2.4** - Calcul de moyenne  
Utilise `Scanner` pour demander à l'utilisateur d'entrer 3 notes. Convertis en `double`, calcule la moyenne et affiche-la avec 2 décimales en utilisant `System.out.printf("%.2f", moyenne)`.

**Exercice 2.5** - Opérations sur variables  
Crée une variable `int compteur = 0`. Incrémente-la de 5 (`compteur += 5`), multiplie-la par 3 (`compteur *= 3`), soustrais 10, divise par 2. Affiche la valeur à chaque étape avec un message explicatif.

**Exercice 2.6** - Calculs avec modulo  
Demande un nombre à l'utilisateur avec `Scanner`. Affiche si ce nombre est pair ou impair en utilisant `%`. Affiche aussi le reste de sa division par 3 et par 5.

**Exercice 2.7** - Types booléens et opérateurs logiques  
Crée des variables booléennes : `boolean estMajeur = true`, `boolean aPermis = false`. Teste et affiche le résultat de : `estMajeur && aPermis`, `estMajeur || aPermis`, `!estMajeur`.

**Exercice 2.8** - Comparaisons  
Crée deux variables `int x = 25` et `int y = 30`. Teste et affiche le résultat de toutes les comparaisons : `==`, `!=`, `<`, `>`, `<=`, `>=` entre x et y.

**Exercice 2.9** - Calcul d'aire  
Demande à l'utilisateur la longueur et la largeur d'un rectangle avec `Scanner`. Calcule et affiche le périmètre et l'aire. Fais de même pour un cercle (utilise `Math.PI` pour π).

**Exercice 2.10** - Conversion température  
Demande une température en Celsius avec `Scanner`. Convertis-la en Fahrenheit (formule : F = C * 9/5 + 32) et en Kelvin (K = C + 273.15). Affiche les trois valeurs avec `printf` formaté.

---

### **Chapitre 3 — Chaînes de caractères (String)**

**Exercice 3.1** - Manipulation basique  
Crée une variable `String phrase = "java est puissant"`. Affiche cette phrase en majuscules avec `.toUpperCase()`, en minuscules avec `.toLowerCase()`, et observe que String est immutable.

**Exercice 3.2** - Longueur et accès aux caractères  
Crée `String mot = "Programmation"`. Affiche la longueur avec `.length()`, le premier caractère avec `.charAt(0)`, le dernier avec `.charAt(mot.length()-1)`, et le 5ème caractère.

**Exercice 3.3** - Substring  
Avec `String texte = "Apprendre Java est passionnant"`, extrais et affiche : les 9 premiers caractères avec `.substring(0, 9)`, les 6 derniers, du caractère 10 à 16, et explore `.substring()` avec un seul paramètre.

**Exercice 3.4** - Méthodes de recherche  
Crée `String phrase = "Je code en Java et j'adore Java"`. Utilise `.indexOf("Java")` pour trouver la première occurrence, `.lastIndexOf("Java")` pour la dernière, et compte manuellement les occurrences en parcourant la chaîne.

**Exercice 3.5** - Split et Join  
Crée `String phrase = "rouge,vert,bleu,jaune"`. Utilise `.split(",")` pour séparer en tableau. Puis utilise `String.join(" - ", tableau)` pour reformer une chaîne avec " - " comme séparateur.

**Exercice 3.6** - Remplacement  
Crée `String texte = "J'aime les bananes et les bananes sont délicieuses"`. Remplace "bananes" par "pommes" avec `.replace()`. Essaie aussi `.replaceFirst()` pour remplacer seulement la première occurrence.

**Exercice 3.7** - Tests de chaînes  
Crée plusieurs chaînes et teste : `.isEmpty()`, `.isBlank()` (Java 11+), `.startsWith()`, `.endsWith()`, `.contains()`, `.equals()` vs `==`. Affiche et explique les résultats.

**Exercice 3.8** - Suppression d'espaces  
Crée `String texte = "   Java   "`. Utilise `.trim()` pour enlever les espaces au début et à la fin. Explore aussi `.strip()`, `.stripLeading()`, `.stripTrailing()` (Java 11+).

**Exercice 3.9** - StringBuilder  
Crée un `StringBuilder sb = new StringBuilder()`. Ajoute plusieurs chaînes avec `.append()`, insère avec `.insert()`, supprime avec `.delete()`, inverse avec `.reverse()`. Convertis en String avec `.toString()`.

**Exercice 3.10** - Formatage avec String.format  
Crée des variables `String nom = "Marie"`, `int age = 25`. Utilise `String.format()` pour créer une phrase formatée : "Je m'appelle %s, j'ai %d ans". Utilise aussi `printf` pour afficher directement avec formatage.

---

### **Chapitre 4 — Tableaux (Arrays)**

**Exercice 4.1** - Création et accès aux tableaux  
Crée un tableau `String[] fruits = {"pomme", "banane", "orange", "kiwi", "mangue"}`. Affiche : le 1er fruit, le dernier avec `fruits[fruits.length-1]`, tous les fruits avec une boucle, et la longueur avec `.length`.

**Exercice 4.2** - Tableaux de primitifs  
Crée `int[] nombres = {10, 20, 30, 40, 50}`. Modifie le 2ème élément en 25, parcours le tableau avec une boucle `for` classique, puis avec une boucle `for-each`. Affiche chaque élément.

**Exercice 4.3** - Initialisation de tableaux  
Crée un tableau `int[] tab = new int[10]`. Initialise chaque élément avec sa position (tab[i] = i). Crée aussi un tableau 2D : `int[][] matrice = new int[3][3]` et initialise-le.

**Exercice 4.4** - Classe Arrays  
Importe `java.util.Arrays`. Crée un tableau `int[] nombres = {5, 2, 8, 1, 9}`. Utilise `Arrays.sort()` pour trier, `Arrays.toString()` pour afficher, `Arrays.copyOf()` pour copier, `Arrays.fill()` pour remplir.

**Exercice 4.5** - Recherche dans tableau  
Crée un tableau de nombres. Écris une méthode qui recherche un élément et retourne son index (ou -1 si non trouvé). Utilise aussi `Arrays.binarySearch()` sur un tableau trié.

**Exercice 4.6** - Tableaux multidimensionnels  
Crée une matrice 3x3 : `int[][] matrice = {{1,2,3}, {4,5,6}, {7,8,9}}`. Accède à l'élément au centre, parcours avec boucles imbriquées, affiche chaque ligne, calcule la somme de tous les éléments.

**Exercice 4.7** - Copie de tableaux  
Crée un tableau. Explore les différentes façons de copier : `Arrays.copyOf()`, `System.arraycopy()`, clone(), et copie manuelle. Modifie le tableau original et vérifie si les copies sont affectées.

**Exercice 4.8** - Tableau de taille dynamique  
Demande à l'utilisateur combien de nombres il veut entrer. Crée un tableau de cette taille avec `new int[taille]`. Remplis-le avec `Scanner`, puis affiche tous les éléments.

**Exercice 4.9** - Comparaison de tableaux  
Crée deux tableaux. Compare-les avec `Arrays.equals()` pour vérifier s'ils sont identiques. Crée aussi deux tableaux 2D et utilise `Arrays.deepEquals()`.

**Exercice 4.10** - Statistiques sur tableau  
Crée un tableau de nombres. Écris des méthodes pour calculer : la somme, la moyenne, le minimum, le maximum, et compter combien d'éléments sont supérieurs à la moyenne.

---

### **Chapitre 5 — Structures de contrôle**

**Exercice 5.1** - If simple  
Demande l'âge de l'utilisateur avec `Scanner`. Si l'âge est >= 18, affiche "Vous êtes majeur", sinon affiche "Vous êtes mineur". Teste avec différentes valeurs.

**Exercice 5.2** - If-else if-else  
Demande une note entre 0 et 20. Affiche la mention avec if-else if : "Excellent" (>= 16), "Bien" (>= 14), "Assez bien" (>= 12), "Passable" (>= 10), "Insuffisant" (< 10).

**Exercice 5.3** - Opérateur ternaire  
Utilise l'opérateur ternaire `? :` pour simplifier un if-else. Exemple : `String message = (age >= 18) ? "Majeur" : "Mineur"`. Crée plusieurs exemples avec opérateurs ternaires.

**Exercice 5.4** - Switch classique  
Demande un jour de la semaine (1-7). Utilise `switch` pour afficher le nom du jour. Utilise `break` pour éviter le fall-through. Teste sans break pour voir ce qui se passe.

**Exercice 5.5** - Switch expressions (Java 12+)  
Réécris l'exercice précédent avec les switch expressions modernes : `String jour = switch(numero) { case 1 -> "Lundi"; case 2 -> "Mardi"; ... }`. Plus concis et sans break.

**Exercice 5.6** - Boucle for classique  
Affiche les nombres de 1 à 10 avec `for`. Affiche les nombres pairs de 0 à 20. Affiche les nombres de 10 à 1 en ordre décroissant. Affiche les multiples de 5 entre 0 et 50.

**Exercice 5.7** - Boucle for-each  
Crée un tableau `String[] fruits = {"pomme", "banane", "orange"}`. Parcours-le avec `for(String fruit : fruits)`. Calcule aussi la longueur totale de tous les fruits combinés.

**Exercice 5.8** - Boucle while  
Crée un compteur initialisé à 0. Avec une boucle `while`, incrémente et affiche jusqu'à 10. Crée aussi un programme qui demande à l'utilisateur d'entrer "stop" pour arrêter la boucle.

**Exercice 5.9** - Break et continue  
Affiche les nombres de 1 à 20, mais saute (`continue`) les multiples de 3 et arrête (`break`) à 15. Crée aussi une boucle qui cherche un nombre dans un tableau et s'arrête quand elle le trouve.

**Exercice 5.10** - Boucles imbriquées  
Crée un programme avec deux boucles `for` imbriquées qui affiche une table de multiplication (de 1 à 10). Format : "3 x 4 = 12". Utilise `printf` pour un affichage aligné.

---

### **Chapitre 6 — Méthodes (fonctions)**

**Exercice 6.1** - Première méthode  
Crée une méthode `static void direBonjour()` qui affiche "Bonjour !". Appelle-la 3 fois depuis `main()`. Crée aussi `static void direBonjour(String nom)` qui affiche "Bonjour [nom] !".

**Exercice 6.2** - Méthodes avec return  
Crée des méthodes : `static int addition(int a, int b)`, `static int multiplication(int a, int b)`, `static int soustraction(int a, int b)`, `static double division(double a, double b)`. Teste-les toutes.

**Exercice 6.3** - Surcharge de méthodes (overloading)  
Crée plusieurs versions de la méthode `add` : `int add(int a, int b)`, `double add(double a, double b)`, `String add(String a, String b)`. Java choisit automatiquement selon les types.

**Exercice 6.4** - Return multiple avec objets  
Puisque Java ne peut retourner qu'une valeur, crée une classe `Rectangle` avec attributs `perimetre` et `aire`. La méthode `calculerRectangle(longueur, largeur)` retourne un objet Rectangle.

**Exercice 6.5** - Méthodes varargs  
Crée une méthode `static int somme(int... nombres)` qui accepte un nombre variable d'arguments et retourne leur somme. Appelle-la avec 2, 3, 5, ou 10 arguments.

**Exercice 6.6** - Méthodes récursives  
Crée une méthode récursive `static int factorielle(int n)` qui calcule n!. Par exemple : 5! = 5 × 4 × 3 × 2 × 1 = 120. Teste avec différentes valeurs et ajoute une condition d'arrêt.

**Exercice 6.7** - Portée des variables  
Démontre la portée : crée une variable locale dans `main`, essaie d'y accéder depuis une méthode (erreur). Crée une variable de classe `static` et accède-y depuis plusieurs méthodes.

**Exercice 6.8** - Passage par valeur  
Crée une méthode qui modifie un paramètre primitif (`int`). Observe que la variable originale ne change pas (passage par valeur). Fais de même avec un objet et observe que ses attributs peuvent changer.

**Exercice 6.9** - Documentation Javadoc  
Écris une méthode `calculerMoyenne(double[] notes)` avec une documentation Javadoc complète : `/** description @param @return */`. Génère la documentation HTML avec `javadoc`.

**Exercice 6.10** - Mini calculatrice avec menu  
Crée un programme avec un menu : 1-Addition, 2-Soustraction, 3-Multiplication, 4-Division, 5-Quitter. Chaque opération est une méthode. Utilise `switch` pour le menu et boucle jusqu'à que l'utilisateur quitte.

---

### **Chapitre 7 — Introduction à la POO**

**Exercice 7.1** - Première classe  
Crée une classe `Personne` avec attributs `String nom` et `int age`. Crée un constructeur, des getters/setters, et une méthode `sePresenter()` qui affiche les infos. Crée 3 instances dans `main()`.

**Exercice 7.2** - Constructeurs multiples  
Crée une classe `Voiture` avec attributs : `marque`, `modele`, `annee`. Crée plusieurs constructeurs (overloading) : sans paramètres, avec marque, avec marque et modele, avec tous les paramètres.

**Exercice 7.3** - Encapsulation  
Crée une classe `CompteBancaire` avec attribut privé `double solde`. Crée des méthodes `deposer(montant)`, `retirer(montant)` qui vérifient que le solde reste positif, et `getSolde()` pour consulter.

**Exercice 7.4** - Méthodes d'instance vs statiques  
Crée une classe `Cercle` avec attribut d'instance `rayon` et méthode `calculerAire()`. Ajoute une méthode `static` qui ne dépend pas de l'instance, comme `static double convertirRadianDegre(double radian)`.

**Exercice 7.5** - This keyword  
Crée une classe où le paramètre du constructeur a le même nom que l'attribut. Utilise `this.nom = nom` pour différencier. Crée aussi une méthode qui retourne `this` pour permettre le method chaining.

**Exercice 7.6** - Compteur d'instances  
Crée une classe `CompteurInstances` avec un attribut de classe `static int compteur`. Incrémente dans le constructeur. Crée plusieurs objets et affiche combien d'instances ont été créées.

**Exercice 7.7** - toString()  
Crée une classe `Livre` avec `titre`, `auteur`, `pages`. Override la méthode `toString()` pour retourner une représentation lisible. Teste en affichant directement l'objet avec `System.out.println(livre)`.

**Exercice 7.8** - Equals et HashCode  
Crée une classe `Point` avec `x` et `y`. Override `equals()` pour comparer deux points. Override aussi `hashCode()` (utilise `Objects.hash(x, y)`). Teste l'égalité entre objets.

**Exercice 7.9** - Composition  
Crée une classe `Moteur` et une classe `Voiture` qui contient un objet `Moteur` (composition). La voiture délègue certaines méthodes au moteur : `demarrer()`, `arreter()`.

**Exercice 7.10** - Classe complète  
Crée une classe `Etudiant` complète avec : attributs privés (nom, prenom, notes[]), constructeur, getters/setters, méthode `ajouterNote()`, `calculerMoyenne()`, `toString()`, et `equals()`.

---

## [IDEE] PARTIE 2 — POO Avancée et Collections

---

### **Chapitre 8 — Héritage**

**Exercice 8.1** - Héritage simple  
Crée une classe `Animal` avec attributs `nom`, `age` et méthode `faireDuBruit()`. Crée des classes `Chien` et `Chat` qui étendent `Animal` et redéfinissent `faireDuBruit()` ("Woof!" et "Meow!").

**Exercice 8.2** - Super keyword  
Crée une classe `Vehicule` avec constructeur `Vehicule(marque, modele)`. Crée `Voiture extends Vehicule` qui ajoute `nbPortes`. Dans le constructeur de Voiture, utilise `super(marque, modele)` puis initialise nbPortes.

**Exercice 8.3** - Héritage multi-niveaux  
Crée une hiérarchie : `EtreVivant` -> `Animal` -> `Mammifere` -> `Chien`. Chaque classe ajoute des attributs/méthodes. Crée une instance de Chien et vérifie qu'elle hérite de tout.

**Exercice 8.4** - Override et annotations  
Crée une classe `Forme` avec méthode `calculerAire()`. Crée des classes `Rectangle`, `Cercle`, `Triangle` qui étendent Forme et override `calculerAire()`. Utilise l'annotation `@Override`.

**Exercice 8.5** - Protected access  
Démontre l'accès `protected` : crée une classe parente avec attribut/méthode protected, accessible dans la classe enfant mais pas de l'extérieur. Compare avec private et public.

**Exercice 8.6** - Final keyword  
Crée une classe avec méthode `final` (ne peut pas être overridden). Crée une classe `final` (ne peut pas être étendue). Crée une variable `final` (constante). Teste les restrictions.

**Exercice 8.7** - Polymorphisme  
Crée une liste `ArrayList<Animal>` contenant des objets `Chien`, `Chat`, `Oiseau`. Parcours la liste et appelle `faireDuBruit()` sur chacun. Chaque animal fait son bruit spécifique (polymorphisme).

**Exercice 8.8** - Instanceof et casting  
Utilise `instanceof` pour vérifier le type réel d'un objet `Animal`. Si c'est un `Chien`, caste-le : `Chien chien = (Chien) animal` pour accéder aux méthodes spécifiques de Chien.

**Exercice 8.9** - Object class  
Toutes les classes héritent de `Object`. Explore les méthodes héritées : `toString()`, `equals()`, `hashCode()`, `getClass()`. Override certaines dans ta classe personnalisée.

**Exercice 8.10** - Système complet avec héritage  
Crée un système de gestion de bibliothèque : classe parente `Document` (titre, auteur, annee), classes enfants `Livre` (pages, isbn), `Magazine` (numero, mois), `DVD` (duree). Chacun implémente `afficherInfo()` différemment.

---

### **Chapitre 9 — Classes abstraites et interfaces**

**Exercice 9.1** - Classe abstraite simple  
Crée une classe abstraite `Forme` avec méthode abstraite `abstract double calculerAire()`. Essaie de l'instancier (erreur). Crée `Carre extends Forme` qui implémente la méthode.

**Exercice 9.2** - Multiple méthodes abstraites  
Crée une classe abstraite `Animal` avec méthodes abstraites `manger()`, `dormir()`, `seDeplacer()`. Crée des classes concrètes `Chien`, `Oiseau`, `Poisson` qui implémentent toutes ces méthodes.

**Exercice 9.3** - Méthodes concrètes dans abstraites  
Crée une classe abstraite `Vehicule` avec une méthode abstraite `demarrer()` et une méthode concrète `arreter()` (implémentée). Les enfants héritent de `arreter()` mais doivent implémenter `demarrer()`.

**Exercice 9.4** - Interface simple  
Crée une interface `Payable` avec méthode `double calculerMontant()`. Crée des classes `Facture` et `Salaire` qui implémentent `Payable`. Une interface est un contrat.

**Exercice 9.5** - Interface avec default methods (Java 8+)  
Crée une interface avec une méthode `default` : `default void afficher() { System.out.println("Affichage par défaut"); }`. Les classes peuvent utiliser cette implémentation ou la override.

**Exercice 9.6** - Méthodes statiques dans interfaces (Java 8+)  
Crée une interface avec une méthode `static` : `static int comparer(int a, int b)`. Les méthodes static sont appelées sur l'interface, pas sur les instances.

**Exercice 9.7** - Implémentation multiple d'interfaces  
Crée deux interfaces : `Nageur` (méthode nager) et `Voleur` (méthode voler). Crée `Canard implements Nageur, Voleur` qui implémente les deux. Java supporte l'implémentation multiple.

**Exercice 9.8** - Interface vs classe abstraite  
Compare : quand utiliser une interface (contrat, comportement) vs classe abstraite (hiérarchie, état partagé). Crée un exemple de chaque et documente les différences.

**Exercice 9.9** - Interface fonctionnelle  
Crée une interface avec une seule méthode abstraite (interface fonctionnelle) : `interface Calculateur { int calculer(int a, int b); }`. Utilise-la avec une lambda : `Calculateur add = (a, b) -> a + b`.

**Exercice 9.10** - Design pattern avec interfaces  
Implémente le pattern Strategy : interface `StrategieCalcul` avec méthode `calculer()`. Crée des implémentations concrètes `Addition`, `Multiplication`. Une classe `Calculatrice` utilise ces stratégies.

---

### **Chapitre 10 — Collections Framework - List**

**Exercice 10.1** - ArrayList basique  
Crée un `ArrayList<String> fruits = new ArrayList<>()`. Utilise `.add()`, `.get()`, `.size()`, `.remove()`, `.clear()`. Compare avec les tableaux : ArrayList est dynamique.

**Exercice 10.2** - Parcours d'ArrayList  
Crée un ArrayList de nombres. Parcours-le avec : boucle `for` classique, boucle `for-each`, `.forEach()` avec lambda, et `Iterator`. Affiche chaque élément.

**Exercice 10.3** - ArrayList d'objets  
Crée une classe `Personne` et un `ArrayList<Personne>`. Ajoute plusieurs personnes, recherche une personne par nom, supprime une personne, trie la liste avec `Collections.sort()`.

**Exercice 10.4** - LinkedList  
Crée un `LinkedList<Integer>`. Compare avec ArrayList : LinkedList est meilleure pour insertions/suppressions, ArrayList meilleure pour accès direct. Utilise `.addFirst()`, `.addLast()`, `.removeFirst()`.

**Exercice 10.5** - Vector et Stack  
Explore `Vector` (ArrayList thread-safe mais obsolète) et `Stack extends Vector`. Crée un Stack, utilise `.push()`, `.pop()`, `.peek()`. Implémente une calculatrice Reverse Polish Notation.

**Exercice 10.6** - Méthodes Collections  
Utilise la classe utilitaire `Collections` : `.sort()`, `.reverse()`, `.shuffle()`, `.binarySearch()`, `.min()`, `.max()`, `.frequency()`. Teste sur différentes listes.

**Exercice 10.7** - Comparator et Comparable  
Crée une classe `Etudiant` qui implémente `Comparable<Etudiant>` (ordre naturel par nom). Crée aussi des `Comparator` pour trier par âge, par moyenne. Utilise avec `Collections.sort()`.

**Exercice 10.8** - Sublist et operations  
Crée une liste. Utilise `.subList(from, to)` pour obtenir une portion. Explore `.contains()`, `.indexOf()`, `.lastIndexOf()`, `.retainAll()`, `.removeAll()`.

**Exercice 10.9** - Conversion List-Array  
Convertis un tableau en List avec `Arrays.asList()`. Convertis une List en tableau avec `.toArray()`. Attention : `Arrays.asList()` retourne une liste de taille fixe.

**Exercice 10.10** - List immutable  
Crée des listes immutables avec `List.of()` (Java 9+) ou `Collections.unmodifiableList()`. Essaie de modifier (exception). Comprends les avantages : thread-safe, sécurité.

---

### **Chapitre 11 — Collections Framework - Set et Map**

**Exercice 11.1** - HashSet basique  
Crée un `HashSet<String>`. Ajoute des éléments avec `.add()`. Essaie d'ajouter des doublons (ignorés). Utilise `.contains()`, `.remove()`, `.size()`. Set n'autorise pas les doublons.

**Exercice 11.2** - TreeSet  
Crée un `TreeSet<Integer>`. Les éléments sont automatiquement triés. Utilise `.first()`, `.last()`, `.headSet()`, `.tailSet()`, `.subSet()`. Compare avec HashSet (non trié).

**Exercice 11.3** - LinkedHashSet  
Crée un `LinkedHashSet`. Maintient l'ordre d'insertion (contrairement à HashSet). Teste en ajoutant des éléments et en les parcourant : l'ordre est préservé.

**Exercice 11.4** - Opérations sur Sets  
Crée deux `HashSet`. Utilise `.addAll()` (union), `.retainAll()` (intersection), `.removeAll()` (différence). Implémente des opérations ensemblistes mathématiques.

**Exercice 11.5** - HashMap basique  
Crée un `HashMap<String, Integer> ages = new HashMap<>()`. Utilise `.put()`, `.get()`, `.containsKey()`, `.containsValue()`, `.remove()`, `.size()`. Map associe clés et valeurs.

**Exercice 11.6** - Parcours de Map  
Parcours un HashMap avec : `.keySet()` (toutes les clés), `.values()` (toutes les valeurs), `.entrySet()` (paires clé-valeur). Utilise `for-each` et `.forEach()` avec lambda.

**Exercice 11.7** - TreeMap  
Crée un `TreeMap<String, Integer>`. Les clés sont automatiquement triées. Utilise `.firstKey()`, `.lastKey()`, `.headMap()`, `.tailMap()`. Utile pour des dictionnaires triés.

**Exercice 11.8** - LinkedHashMap  
Crée un `LinkedHashMap`. Maintient l'ordre d'insertion des clés. Teste aussi le mode LRU (Least Recently Used) pour un cache avec constructeur spécial.

**Exercice 11.9** - Map methods (Java 8+)  
Utilise les nouvelles méthodes : `.getOrDefault()`, `.putIfAbsent()`, `.computeIfAbsent()`, `.computeIfPresent()`, `.merge()`, `.replaceAll()`. Très utiles pour simplifier le code.

**Exercice 11.10** - Compteur avec Map  
Crée une String. Compte les occurrences de chaque caractère avec une `HashMap<Character, Integer>`. Utilise `.merge(char, 1, Integer::sum)` pour simplifier.

---

### **Chapitre 12 — Gestion des exceptions**

**Exercice 12.1** - Try-catch simple  
Demande deux nombres et divise-les. Utilise `try-catch` pour capturer `ArithmeticException` (division par zéro) et `InputMismatchException` (entrée invalide). Affiche des messages appropriés.

**Exercice 12.2** - Multiple catch blocks  
Crée un programme qui accède à un tableau par index. Capture `ArrayIndexOutOfBoundsException` et `NumberFormatException` dans des blocs catch séparés. Affiche un message spécifique pour chaque erreur.

**Exercice 12.3** - Try-catch-finally  
Demande un nombre. Dans `try` : convertis en int. Dans `catch` : gère l'erreur. Dans `finally` : affiche "Opération terminée" (exécuté toujours, même avec exception ou return).

**Exercice 12.4** - Throws clause  
Crée une méthode `diviser(int a, int b) throws ArithmeticException` qui lève l'exception au lieu de la gérer. L'appelant doit gérer avec try-catch ou propager avec throws.

**Exercice 12.5** - Throw keyword  
Crée une méthode `verifierAge(int age)` qui lève une exception avec `throw new IllegalArgumentException("Âge invalide")` si l'âge est négatif ou > 150. Appelle et capture.

**Exercice 12.6** - Exception personnalisée  
Crée ta propre exception : `class AgeInvalideException extends Exception`. Crée constructeur avec message. Lance-la avec `throw` et capture-la avec `try-catch`.

**Exercice 12.7** - Checked vs Unchecked  
Comprends la différence : checked (IOException, SQLException) doivent être gérées, unchecked (RuntimeException) peuvent être ignorées. Crée des exemples de chaque.

**Exercice 12.8** - Try-with-resources  
Utilise try-with-resources pour gérer automatiquement la fermeture : `try(Scanner sc = new Scanner(System.in))`. Le scanner est fermé automatiquement. Teste avec fichiers.

**Exercice 12.9** - Multi-catch (Java 7+)  
Capture plusieurs exceptions dans un seul catch : `catch(IOException | SQLException e)`. Simplifie le code quand le traitement est identique pour plusieurs exceptions.

**Exercice 12.10** - Programme robuste  
Crée un programme de gestion de notes qui gère TOUTES les erreurs possibles : entrées invalides, divisions par zéro, indices hors limites, fichiers manquants. Ne doit jamais crasher.

---

### **Chapitre 13 — Entrées/Sorties (I/O)**

**Exercice 13.1** - Lire un fichier texte  
Utilise `BufferedReader` et `FileReader` pour lire un fichier ligne par ligne :
```java
try(BufferedReader br = new BufferedReader(new FileReader("fichier.txt"))) {
    String ligne;
    while((ligne = br.readLine()) != null) {
        System.out.println(ligne);
    }
}
```

**Exercice 13.2** - Écrire dans un fichier  
Utilise `BufferedWriter` et `FileWriter` pour écrire dans un fichier. Demande à l'utilisateur son nom et âge, écris-les dans `info.txt`. Ferme le fichier avec try-with-resources.

**Exercice 13.3** - Append à un fichier  
Ouvre un fichier en mode append : `new FileWriter("journal.txt", true)`. Ajoute des lignes sans écraser le contenu existant. Crée un journal avec horodatage.

**Exercice 13.4** - Scanner avec fichier  
Utilise `Scanner` pour lire un fichier : `Scanner sc = new Scanner(new File("data.txt"))`. Plus simple que BufferedReader. Lis mot par mot avec `.next()` ou ligne par ligne avec `.nextLine()`.

**Exercice 13.5** - Files class (Java 7+)  
Utilise `java.nio.file.Files` : `.readAllLines()` (lit tout en List), `.write()`, `.copy()`, `.delete()`, `.exists()`. API moderne plus simple que java.io.

**Exercice 13.6** - Path et Paths  
Utilise `Path` pour manipuler chemins : `Path p = Paths.get("dossier", "fichier.txt")`. Utilise `.getFileName()`, `.getParent()`, `.toAbsolutePath()`, `.resolve()`, `.relativize()`.

**Exercice 13.7** - Fichiers binaires  
Utilise `FileInputStream` et `FileOutputStream` pour lire/écrire des fichiers binaires. Copie une image en lisant byte par byte. Compare avec Files.copy().

**Exercice 13.8** - Sérialisation  
Crée une classe `Personne implements Serializable`. Sauvegarde un objet dans un fichier avec `ObjectOutputStream`. Recharge-le avec `ObjectInputStream`. L'objet est persisté.

**Exercice 13.9** - Gestion d'erreurs I/O  
Crée un programme qui demande un nom de fichier. Gère `FileNotFoundException`, `IOException`. Si le fichier n'existe pas, propose de le créer. Robustesse complète.

**Exercice 13.10** - Traitement de fichier complet  
Crée un fichier texte avec plusieurs paragraphes. Écris un programme qui : compte lignes/mots/caractères, trouve le mot le plus long, compte les occurrences de chaque mot, écrit les stats dans un nouveau fichier.

---

### **Chapitre 14 — Génériques (Generics)**

**Exercice 14.1** - Classe générique simple  
Crée une classe générique `Boite<T>` avec un attribut `T contenu`. Méthodes : `set(T contenu)`, `T get()`. Crée des instances : `Boite<String>`, `Boite<Integer>`, `Boite<Personne>`.

**Exercice 14.2** - Méthode générique  
Crée une méthode statique générique : `static <T> void afficher(T element)`. La méthode fonctionne avec n'importe quel type. Teste avec String, Integer, custom objects.

**Exercice 14.3** - Génériques multiples  
Crée une classe `Paire<K, V>` avec deux types génériques (comme Map.Entry). Attributs : `K cle` et `V valeur`. Crée des paires de différents types.

**Exercice 14.4** - Bounded type parameters  
Crée une méthode `<T extends Number> double calculerMoyenne(T[] nombres)`. Le type T doit étendre Number. Fonctionne avec Integer[], Double[], mais pas String[].

**Exercice 14.5** - Wildcards  
Comprends `?` (wildcard) : `List<?>` (n'importe quel type), `List<? extends Number>` (Number ou sous-classes), `List<? super Integer>` (Integer ou super-classes). Crée des exemples.

**Exercice 14.6** - Generic ArrayList  
Crée ta propre version simplifiée de ArrayList : `class MaListe<E>` avec un tableau interne, méthodes `add()`, `get()`, `size()`. Gère le redimensionnement automatique.

**Exercice 14.7** - Comparable générique  
Crée une méthode générique `<T extends Comparable<T>> T max(T a, T b)` qui retourne le plus grand élément. Fonctionne avec tous types qui implémentent Comparable.

**Exercice 14.8** - Type erasure  
Comprends le type erasure : les génériques sont vérifiés à la compilation mais effacés au runtime. `List<String>` et `List<Integer>` deviennent `List` au runtime. Démontre avec `.getClass()`.

**Exercice 14.9** - Generic interface  
Crée une interface générique : `interface Conteneur<T> { void ajouter(T item); T retirer(); }`. Crée une implémentation concrète qui spécifie le type ou reste générique.

**Exercice 14.10** - Complex generic structure  
Crée un système générique complet : une classe `Repository<T>` qui gère une collection d'objets, avec méthodes CRUD, filtrage avec Predicate, tri avec Comparator. Teste avec différents types.

---

## [WEB] PARTIE 3 — Java Moderne et Programmation Fonctionnelle

---

### **Chapitre 15 — Lambda expressions et programmation fonctionnelle**

**Exercice 15.1** - Première lambda  
Crée une interface fonctionnelle `interface Calculateur { int calculer(int a, int b); }`. Utilise une lambda : `Calculateur add = (a, b) -> a + b`. Teste-la. Plus concis qu'une classe anonyme.

**Exercice 15.2** - Lambda avec Runnable  
Crée un thread avec lambda : `new Thread(() -> System.out.println("Hello")).start()`. Compare avec la version traditionnelle utilisant une classe anonyme.

**Exercice 15.3** - Lambda avec Comparator  
Trie une liste avec lambda : `list.sort((a, b) -> a.compareTo(b))`. Ou plus simple : `list.sort(String::compareTo)` (method reference). Teste différentes lambdas de tri.

**Exercice 15.4** - Interfaces fonctionnelles standards  
Utilise les interfaces du package `java.util.function` : `Predicate<T>` (test), `Function<T,R>` (transformation), `Consumer<T>` (action), `Supplier<T>` (génération). Crée des exemples de chaque.

**Exercice 15.5** - Method references  
Utilise les références de méthodes : `String::toUpperCase`, `System.out::println`, `ArrayList::new`. 4 types : static, instance, instance d'un objet, constructor. Crée un exemple de chaque.

**Exercice 15.6** - Lambda avec forEach  
Parcours une collection avec `list.forEach(element -> System.out.println(element))` ou `list.forEach(System.out::println)`. Plus concis que for-each traditionnel.

**Exercice 15.7** - Scope dans lambdas  
Explore le scope : lambdas peuvent accéder aux variables locales (effectively final), aux attributs de classe. Essaie de modifier une variable locale (erreur). Comprends les closures.

**Exercice 15.8** - Composition de fonctions  
Utilise `.andThen()` et `.compose()` pour composer des Functions : `Function<Integer, Integer> f = x -> x * 2; Function<Integer, Integer> g = x -> x + 1; f.andThen(g).apply(3)`.

**Exercice 15.9** - Predicate composition  
Combine des Predicates avec `.and()`, `.or()`, `.negate()` : `Predicate<Integer> estPair = n -> n % 2 == 0; Predicate<Integer> estPositif = n -> n > 0; estPair.and(estPositif)`.

**Exercice 15.10** - Programmation fonctionnelle complète  
Crée un système de traitement de commandes avec lambdas : filtrage (Predicate), transformation (Function), accumulation (Collector). Style purement fonctionnel sans boucles.

---

### **Chapitre 16 — Streams API**

**Exercice 16.1** - Premier Stream  
Crée un Stream depuis une liste : `list.stream()`. Utilise `.forEach()` pour afficher chaque élément. Comprends qu'un Stream est une séquence d'opérations sur une collection.

**Exercice 16.2** - Filter et count  
Crée une liste de nombres. Filtre les pairs : `list.stream().filter(n -> n % 2 == 0)`. Compte-les avec `.count()`. Affiche-les avec `.forEach()`.

**Exercice 16.3** - Map transformation  
Transforme chaque élément avec `.map()` : `list.stream().map(String::toUpperCase)`. Crée une liste de nombres et génère leurs carrés. Collecte le résultat avec `.collect(Collectors.toList())`.

**Exercice 16.4** - Sorted et distinct  
Trie un Stream avec `.sorted()` ou `.sorted(comparator)`. Élimine les doublons avec `.distinct()`. Chaîne plusieurs opérations : `stream().distinct().sorted().collect()`.

**Exercice 16.5** - Limit et skip  
Utilise `.limit(n)` pour prendre seulement n éléments, `.skip(n)` pour sauter n éléments. Implémente la pagination : skip(page*size).limit(size).

**Exercice 16.6** - Reduce  
Utilise `.reduce()` pour accumuler : `stream.reduce(0, (a, b) -> a + b)` calcule la somme. Calcule aussi le produit, trouve le max/min avec reduce.

**Exercice 16.7** - Collectors avancés  
Utilise différents Collectors : `.toList()`, `.toSet()`, `.joining()`, `.groupingBy()`, `.partitioningBy()`, `.counting()`, `.averaging()`. Crée des statistiques sur une collection.

**Exercice 16.8** - FlatMap  
Utilise `.flatMap()` pour aplatir des Streams imbriqués : `List<List<Integer>>` -> `Stream<Integer>`. Exemple : liste de listes de mots vers stream de tous les mots.

**Exercice 16.9** - Parallel Streams  
Utilise `.parallelStream()` au lieu de `.stream()` pour traiter en parallèle. Mesure la différence de performance sur gros volume. Attention aux effets de bord.

**Exercice 16.10** - Pipeline complet  
Crée un pipeline Stream complexe : à partir d'une liste de personnes, filtre par âge, transforme en noms, trie, collecte en Set. Tout en une seule expression chaînée.

---

### **Chapitre 17 — Optional**

**Exercice 17.1** - Optional basique  
Crée un `Optional<String> opt = Optional.of("valeur")`. Utilise `.isPresent()`, `.isEmpty()`, `.get()`. Comprends que Optional évite les null et NullPointerException.

**Exercice 17.2** - Optional.empty et ofNullable  
Crée `Optional.empty()` (pas de valeur). Utilise `Optional.ofNullable(valeur)` qui crée empty si valeur est null. Teste avec valeurs null et non-null.

**Exercice 17.3** - orElse et orElseGet  
Utilise `.orElse(defaultValue)` pour fournir une valeur par défaut. Utilise `.orElseGet(() -> defaultValue)` quand la création est coûteuse (lazy). Compare les deux.

**Exercice 17.4** - orElseThrow  
Utilise `.orElseThrow()` pour lancer une exception si vide : `.orElseThrow(() -> new NoSuchElementException("Pas trouvé"))`. Gestion d'erreurs élégante.

**Exercice 17.5** - ifPresent et ifPresentOrElse  
Utilise `.ifPresent(value -> System.out.println(value))` pour agir si présent. Utilise `.ifPresentOrElse(action, emptyAction)` (Java 9+) pour les deux cas.

**Exercice 17.6** - map et flatMap  
Transforme la valeur avec `.map()` : `opt.map(String::toUpperCase)`. Utilise `.flatMap()` quand la transformation retourne un Optional. Chaîne plusieurs transformations.

**Exercice 17.7** - filter  
Filtre un Optional avec `.filter(predicate)` : `opt.filter(s -> s.length() > 5)`. Retourne empty si ne satisfait pas le prédicat.

**Exercice 17.8** - Optional avec Streams  
Utilise Optional dans un Stream : `.map(Optional::ofNullable).filter(Optional::isPresent).map(Optional::get)`. Ou avec `.flatMap(Optional::stream)` (Java 9+).

**Exercice 17.9** - Éviter les null checks  
Réécris du code avec null checks imbriqués en utilisant Optional et chaînage. Compare la lisibilité et la sûreté du code.

**Exercice 17.10** - Best practices  
Documente les bonnes pratiques : jamais Optional dans attributs de classe, jamais en paramètre de méthode, toujours en return type. Utilise pour éviter null, pas pour remplacer null partout.

---

### **Chapitre 18 — Date et Time API (java.time)**

**Exercice 18.1** - LocalDate  
Utilise `LocalDate` pour les dates sans heure : `LocalDate.now()`, `.of(2024, 1, 15)`, `.parse("2024-01-15")`. Opérations : `.plusDays()`, `.minusMonths()`, `.isAfter()`, `.isBefore()`.

**Exercice 18.2** - LocalTime  
Utilise `LocalTime` pour l'heure sans date : `LocalTime.now()`, `.of(14, 30, 0)`, `.parse("14:30")`. Opérations : `.plusHours()`, `.minusMinutes()`, formatage avec `DateTimeFormatter`.

**Exercice 18.3** - LocalDateTime  
Combine date et heure : `LocalDateTime.now()`, `.of(date, time)`. Convertis entre LocalDate, LocalTime et LocalDateTime : `.atTime()`, `.toLocalDate()`, `.toLocalTime()`.

**Exercice 18.4** - ZonedDateTime  
Gère les fuseaux horaires : `ZonedDateTime.now(ZoneId.of("Europe/Paris"))`. Convertis entre zones : `.withZoneSameInstant(ZoneId.of("America/New_York"))`. Liste toutes les zones : `ZoneId.getAvailableZoneIds()`.

**Exercice 18.5** - Period et Duration  
`Period` pour dates (jours, mois, années) : `Period.between(date1, date2)`, `.getDays()`, `.getMonths()`. `Duration` pour temps (heures, minutes, secondes) : `Duration.between(time1, time2)`, `.toHours()`.

**Exercice 18.6** - Formatting et Parsing  
Utilise `DateTimeFormatter` : formatters prédéfinis (`ISO_DATE`, `ISO_TIME`) ou custom : `DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm")`. Parse et formate des dates.

**Exercice 18.7** - Instant  
`Instant` représente un point dans le temps (timestamp) : `Instant.now()`, `.toEpochMilli()`. Convertis entre Instant et ZonedDateTime. Utile pour logs, bases de données.

**Exercice 18.8** - Calculs de dates  
Calcule : âge d'une personne, nombre de jours entre deux dates, ajoute 3 mois à une date, trouve le premier jour du mois suivant, compte les weekends entre deux dates.

**Exercice 18.9** - TemporalAdjusters  
Utilise `TemporalAdjusters` pour manipulations complexes : `.firstDayOfMonth()`, `.lastDayOfYear()`, `.nextOrSame(DayOfWeek.MONDAY)`. Crée ton propre TemporalAdjuster.

**Exercice 18.10** - Migration depuis java.util.Date  
Convertis entre ancien et nouveau API : `Date.from(instant)`, `date.toInstant()`. Crée un utilitaire de conversion. Documente pourquoi le nouveau API est meilleur (immutable, thread-safe, clair).

---

### **Chapitre 19 — Annotations**

**Exercice 19.1** - Annotations standards  
Utilise les annotations built-in : `@Override`, `@Deprecated`, `@SuppressWarnings`, `@FunctionalInterface`. Comprends leur utilité et comment le compilateur les utilise.

**Exercice 19.2** - Première annotation custom  
Crée une annotation simple : `@interface MaAnnotation { }`. Applique-la à une classe : `@MaAnnotation public class Test { }`. C'est juste un marqueur pour l'instant.

**Exercice 19.3** - Annotation avec éléments  
Crée une annotation avec éléments : `@interface Info { String auteur(); String date(); int version() default 1; }`. Utilise : `@Info(auteur="Ali", date="2024-01-15")`.

**Exercice 19.4** - Retention policy  
Utilise `@Retention` pour spécifier quand l'annotation est disponible : `RetentionPolicy.SOURCE` (compilation), `RUNTIME` (reflection). Teste avec reflection.

**Exercice 19.5** - Target  
Utilise `@Target` pour spécifier où l'annotation peut être appliquée : `ElementType.TYPE` (classe), `METHOD`, `FIELD`, `PARAMETER`. Crée des annotations spécifiques.

**Exercice 19.6** - Reflection et annotations  
Utilise reflection pour lire les annotations au runtime : `Class.isAnnotationPresent()`, `.getAnnotation()`, `.getDeclaredMethods()`. Crée un système qui traite les annotations.

**Exercice 19.7** - Inherited et Documented  
Utilise `@Inherited` pour que les sous-classes héritent de l'annotation. Utilise `@Documented` pour inclure dans la Javadoc. Teste l'héritage d'annotations.

**Exercice 19.8** - Repeatable annotations  
Utilise `@Repeatable` (Java 8+) pour permettre plusieurs annotations identiques : `@Role("admin") @Role("user") class User`. Crée un conteneur pour les annotations répétées.

**Exercice 19.9** - Annotation processor  
Crée un processeur d'annotations basique qui génère du code à la compilation. Utilise l'API `javax.annotation.processing.Processor`. Exemple : générer des getters/setters.

**Exercice 19.10** - Framework avec annotations  
Crée un mini-framework utilisant annotations : `@Entity`, `@Column` pour ORM simple, ou `@Test`, `@BeforeEach` pour testing. Utilise reflection pour exécuter selon annotations.

---

### **Chapitre 20 — Enums**

**Exercice 20.1** - Enum simple  
Crée un enum `enum Jour { LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE }`. Utilise : `Jour j = Jour.LUNDI`, compare avec `==`, parcours avec `.values()`.

**Exercice 20.2** - Enum avec méthodes  
Ajoute des méthodes à ton enum : `boolean estWeekend()`, `boolean estJourOuvrable()`. Les enums sont des classes, elles peuvent avoir des méthodes.

**Exercice 20.3** - Enum avec constructeur  
Crée `enum Taille { PETIT(1), MOYEN(2), GRAND(3); private int valeur; Taille(int valeur) { this.valeur = valeur; } }`. Ajoute getter pour valeur.

**Exercice 20.4** - Enum avec méthodes abstraites  
Chaque constante peut avoir sa propre implémentation : `enum Operation { PLUS {double appliquer(double x, double y) { return x + y; }}, MINUS {...} }`.

**Exercice 20.5** - Switch avec enum  
Utilise enum dans switch : `switch(jour) { case LUNDI: ...; case MARDI: ...; }`. Avec switch expressions (Java 12+) : `String msg = switch(jour) { case LUNDI -> "Début"; ... }`.

**Exercice 20.6** - Enum methods  
Utilise les méthodes héritées : `.name()`, `.ordinal()`, `.valueOf(String)`, `.values()`, `.compareTo()`. Crée un programme qui teste toutes ces méthodes.

**Exercice 20.7** - EnumSet et EnumMap  
Utilise `EnumSet` (implémentation Set optimisée pour enums) : `EnumSet.of(Jour.LUNDI, Jour.MARDI)`. Utilise `EnumMap` (Map optimisée) : `new EnumMap<>(Jour.class)`.

**Exercice 20.8** - Enum implements interface  
Crée une interface `Affichable` et fais implémenter par ton enum. Chaque constante ou l'enum entier peut implémenter l'interface.

**Exercice 20.9** - Singleton avec enum  
Utilise enum pour implémenter le pattern Singleton (meilleure pratique en Java) : `enum Singleton { INSTANCE; }`. Thread-safe, sérialization-safe automatiquement.

**Exercice 20.10** - Système complet avec enums  
Crée un système de commande avec enums : `StatutCommande` (PENDING, CONFIRMED, SHIPPED, DELIVERED), `TypePaiement`, `Priorite`. Utilise dans une classe Commande complète.

---

## [BOITE_A_OUTILS] PARTIE 4 — Java Entreprise et Frameworks

---

### **Chapitre 21 — JDBC et Bases de Données**

**Exercice 21.1** - Connexion JDBC basique  
Établis une connexion à une base SQLite : `Connection conn = DriverManager.getConnection("jdbc:sqlite:test.db")`. Crée une table avec `Statement` et `.executeUpdate()`.

**Exercice 21.2** - INSERT avec Statement  
Insère des données : `stmt.executeUpdate("INSERT INTO users (nom, age) VALUES ('Ali', 25)")`. Insère plusieurs enregistrements. Attention : vulnérable aux injections SQL.

**Exercice 21.3** - PreparedStatement  
Utilise `PreparedStatement` pour éviter l'injection SQL : `PreparedStatement ps = conn.prepareStatement("INSERT INTO users VALUES (?, ?)")`. Utilise `.setString()`, `.setInt()`, `.executeUpdate()`.

**Exercice 21.4** - SELECT et ResultSet  
Exécute une requête SELECT : `ResultSet rs = stmt.executeQuery("SELECT * FROM users")`. Parcours avec `while(rs.next())`, récupère données avec `.getString()`, `.getInt()`.

**Exercice 21.5** - UPDATE et DELETE  
Modifie et supprime des données avec PreparedStatement : `UPDATE users SET age = ? WHERE nom = ?` et `DELETE FROM users WHERE id = ?`. Vérifie le nombre de lignes affectées.

**Exercice 21.6** - Transactions  
Gère les transactions : `conn.setAutoCommit(false)`, effectue plusieurs opérations, `conn.commit()` si tout ok, `conn.rollback()` si erreur. Garantis la cohérence des données.

**Exercice 21.7** - Métadonnées  
Utilise `DatabaseMetaData` pour obtenir infos sur la base : nom, version, tables disponibles. Utilise `ResultSetMetaData` pour obtenir infos sur les colonnes d'un ResultSet.

**Exercice 21.8** - Batch processing  
Utilise `.addBatch()` et `.executeBatch()` pour exécuter plusieurs requêtes en une fois. Plus efficace que des executeUpdate() multiples. Insère 1000 enregistrements rapidement.

**Exercice 21.9** - Connection pooling  
Utilise HikariCP ou Apache DBCP2 pour créer un pool de connexions. Compare les performances avec/sans pooling. Essentiel en production.

**Exercice 21.10** - DAO pattern  
Implémente le pattern DAO (Data Access Object) : interface `UserDAO` avec méthodes CRUD, implémentation `UserDAOImpl` qui encapsule tout le code JDBC. Séparation des responsabilités.

---

### **Chapitre 22 — Servlets et JSP**

**Exercice 22.1** - Premier Servlet  
Crée un Servlet : `public class HelloServlet extends HttpServlet`. Override `doGet()` : `response.getWriter().println("Hello from Servlet!")`. Configure dans web.xml ou avec `@WebServlet("/hello")`.

**Exercice 22.2** - Paramètres de requête  
Récupère les paramètres : `request.getParameter("nom")`. Crée un formulaire HTML qui envoie des données. Le servlet les récupère et affiche.

**Exercice 22.3** - doPost vs doGet  
Crée un formulaire avec méthode POST. Override `doPost()` dans le servlet. Comprends la différence : GET pour récupérer, POST pour modifier/créer.

**Exercice 22.4** - Session  
Utilise `HttpSession` : `request.getSession()`, `.setAttribute()`, `.getAttribute()`. Crée un système de login simple qui stocke l'utilisateur en session.

**Exercice 22.5** - Cookies  
Crée et lit des cookies : `Cookie c = new Cookie("nom", "valeur")`, `response.addCookie(c)`. Récupère avec `request.getCookies()`. Gère l'expiration.

**Exercice 22.6** - Redirection et forward  
Utilise `response.sendRedirect("page.jsp")` (côté client) vs `request.getRequestDispatcher("page.jsp").forward()` (côté serveur). Comprends les différences.

**Exercice 22.7** - Première JSP  
Crée une page JSP : HTML + code Java entre `<% %>`. Utilise expressions `<%= variable %>` et scriptlets. Compare avec servlets : JSP mieux pour la présentation.

**Exercice 22.8** - JSTL et EL  
Utilise JSTL (JSP Standard Tag Library) et EL (Expression Language) : `${user.nom}`, `<c:forEach>`, `<c:if>`. Plus propre que les scriptlets.

**Exercice 22.9** - MVC avec Servlet/JSP  
Implémente MVC : Servlet (Controller) traite la requête, appelle le Model (classes Java/DAO), transmet à la View (JSP). Sépare logique et présentation.

**Exercice 22.10** - Mini application web  
Crée une application complète : liste de tâches avec ajout/suppression, persistance en base JDBC, sessions pour utilisateurs, JSP pour affichage. Architecture MVC propre.

---

### **Chapitre 23 — Maven et Gestion de Dépendances**

**Exercice 23.1** - Premier projet Maven  
Crée un projet Maven : `mvn archetype:generate`. Explore la structure : `pom.xml`, `src/main/java`, `src/test/java`. Compile avec `mvn compile`, exécute tests avec `mvn test`.

**Exercice 23.2** - pom.xml basique  
Édite `pom.xml` : définis `groupId`, `artifactId`, `version`. Ajoute des propriétés comme `maven.compiler.source` et `maven.compiler.target` pour la version Java.

**Exercice 23.3** - Ajouter dépendances  
Ajoute des dépendances dans `<dependencies>` : JUnit, Apache Commons, Gson. Maven les télécharge automatiquement depuis Maven Central. Utilise-les dans ton code.

**Exercice 23.4** - Scopes de dépendances  
Comprends les scopes : `compile` (défaut, partout), `test` (seulement tests), `provided` (fourni par serveur), `runtime` (seulement exécution). Teste différents scopes.

**Exercice 23.5** - Plugins Maven  
Configure des plugins : `maven-compiler-plugin` (version Java), `maven-surefire-plugin` (tests), `maven-jar-plugin` (création JAR). Explore le cycle de vie Maven.

**Exercice 23.6** - Profiles Maven  
Crée des profiles pour différents environnements : `<profiles>` dev, test, prod. Active avec `mvn -P prod`. Configure différentes propriétés par environnement.

**Exercice 23.7** - Maven multi-modules  
Crée un projet parent avec plusieurs modules : `common`, `api`, `web`. Le parent gère les versions communes. Build tout avec `mvn install` depuis le parent.

**Exercice 23.8** - Repository local et remote  
Comprends le repository local `~/.m2/repository`. Configure un repository d'entreprise (Nexus, Artifactory) dans `settings.xml`. Déploie ton artifact avec `mvn deploy`.

**Exercice 23.9** - Maven vs Gradle  
Compare Maven (XML, convention) avec Gradle (Groovy/Kotlin, flexible). Crée le même projet avec les deux. Documente avantages/inconvénients de chaque.

**Exercice 23.10** - Build complet  
Configure un build complet : compilation, tests unitaires, tests d'intégration, génération Javadoc, création JAR exécutable avec dépendances, génération rapport de couverture. Pipeline Maven complet.

---

### **Chapitre 24 — JUnit et Tests Unitaires**

**Exercice 24.1** - Premier test JUnit  
Crée une classe de test avec JUnit 5 : `@Test void testAddition() { assertEquals(4, 2 + 2); }`. Lance avec Maven `mvn test` ou IDE. Le test doit passer.

**Exercice 24.2** - Assertions variées  
Utilise différentes assertions : `assertEquals`, `assertNotEquals`, `assertTrue`, `assertFalse`, `assertNull`, `assertNotNull`, `assertThrows`, `assertArrayEquals`. Teste une classe Calculator.

**Exercice 24.3** - @BeforeEach et @AfterEach  
Utilise `@BeforeEach` pour initialiser des données avant chaque test, `@AfterEach` pour nettoyer. Crée aussi `@BeforeAll` et `@AfterAll` (static) pour setup/teardown une fois.

**Exercice 24.4** - Test exceptions  
Teste qu'une exception est levée : `assertThrows(IllegalArgumentException.class, () -> method())`. Vérifie aussi le message : `assertEquals("message attendu", exception.getMessage())`.

**Exercice 24.5** - Parameterized tests  
Utilise `@ParameterizedTest` avec `@ValueSource`, `@CsvSource`, `@MethodSource` pour tester avec plusieurs jeux de données en un seul test. Évite la duplication.

**Exercice 24.6** - @Disabled et @DisplayName  
Utilise `@Disabled("Raison")` pour ignorer temporairement un test. Utilise `@DisplayName("Description lisible")` pour nommer les tests de façon descriptive.

**Exercice 24.7** - Assumptions  
Utilise `Assumptions.assumeTrue()` pour exécuter un test seulement si une condition est vraie. Utile pour tests dépendant de l'environnement.

**Exercice 24.8** - Mocking avec Mockito  
Installe Mockito. Crée un mock : `MyService mock = Mockito.mock(MyService.class)`. Définis le comportement : `when(mock.method()).thenReturn(value)`. Vérifie les appels : `verify(mock).method()`.

**Exercice 24.9** - Test coverage  
Utilise JaCoCo pour mesurer la couverture de code. Configure dans Maven. Génère le rapport. Vise >80% de couverture. Identifie le code non testé.

**Exercice 24.10** - TDD complet  
Pratique le TDD (Test-Driven Development) : écris le test d'abord (échoue), implémente le minimum pour que ça passe, refactorise. Crée une classe `StringUtils` en TDD complet.

---

### **Chapitre 25 — Logging**

**Exercice 25.1** - java.util.logging  
Utilise le logging natif : `Logger logger = Logger.getLogger(MaClasse.class.getName())`. Log à différents niveaux : `SEVERE`, `WARNING`, `INFO`, `CONFIG`, `FINE`, `FINER`, `FINEST`.

**Exercice 25.2** - Configuration logging  
Configure avec `logging.properties` : niveau global, niveau par package, format de sortie, handlers (console, fichier). Charge avec `-Djava.util.logging.config.file`.

**Exercice 25.3** - Log4j2  
Installe Log4j2 (via Maven). Utilise : `Logger logger = LogManager.getLogger()`. Log : `logger.debug()`, `.info()`, `.warn()`, `.error()`, `.fatal()`.

**Exercice 25.4** - Configuration Log4j2  
Crée `log4j2.xml` : configure appenders (console, fichier, rolling), loggers, niveaux par package, patterns de format. Recharge sans redémarrer l'app.

**Exercice 25.5** - SLF4J facade  
Utilise SLF4J (Simple Logging Facade) : abstraction sur les implémentations. Code avec `org.slf4j.Logger`, choisis l'implémentation (Logback, Log4j2) au runtime via Maven.

**Exercice 25.6** - Logback  
Configure Logback : `logback.xml`. Appenders : console avec couleurs, fichier avec rotation, async. Encoders avec patterns. Filtres pour séparer erreurs/info.

**Exercice 25.7** - Structured logging  
Log en JSON pour parsing facile : configure Log4j2 JsonLayout ou Logback JsonEncoder. Utile pour ElasticSearch/Splunk. Chaque log = objet JSON structuré.

**Exercice 25.8** - MDC (Mapped Diagnostic Context)  
Utilise MDC pour ajouter du contexte : `MDC.put("requestId", uuid)`. Tous les logs incluent automatiquement cette info. Pratique pour tracer une requête à travers l'app.

**Exercice 25.9** - Performance logging  
Log de performance ne doit pas ralentir l'app : utilise niveaux appropriés (debug/trace en dev, pas en prod), async appenders, lazy evaluation : `logger.debug(() -> expensiveOperation())`.

**Exercice 25.10** - Logging best practices  
Documente les bonnes pratiques : niveaux appropriés (ERROR pour erreurs vraies, pas exceptions gérées), messages clairs, pas de données sensibles, performance, rotation des logs, centralisation.

---

## [RAPIDE] PARTIE 5 — Frameworks et Technologies Avancées

---

### **Chapitre 26 — Spring Core**

**Exercice 26.1** - Premier projet Spring  
Crée un projet Spring avec Spring Initializr. Ajoute dépendance `spring-context`. Crée une classe bean `HelloService` et configure-la dans un fichier de configuration ou avec annotations.

**Exercice 26.2** - Dependency Injection avec XML  
Configure des beans dans `applicationContext.xml` : `<bean id="service" class="...">`. Injecte des dépendances avec `<property>` (setter) ou `<constructor-arg>`. Charge le contexte : `new ClassPathXmlApplicationContext()`.

**Exercice 26.3** - Annotations-based configuration  
Utilise `@Component`, `@Service`, `@Repository`, `@Controller` pour auto-détecter les beans. Configure `<context:component-scan>` ou `@ComponentScan`. Plus moderne que XML.

**Exercice 26.4** - @Autowired  
Injecte des dépendances avec `@Autowired` : sur constructeur (recommandé), setter, ou champ. Spring injecte automatiquement. Utilise `@Qualifier` si plusieurs beans du même type.

**Exercice 26.5** - Java-based configuration  
Configure avec Java : classe `@Configuration` avec méthodes `@Bean`. Retourne des instances de beans. Charge avec `AnnotationConfigApplicationContext`. Plus typé que XML.

**Exercice 26.6** - Bean scopes  
Explore les scopes : `singleton` (défaut, une instance), `prototype` (nouvelle instance à chaque demande), `request`, `session`, `application` (web). Configure avec `@Scope`.

**Exercice 26.7** - Lifecycle callbacks  
Gère le lifecycle des beans : méthodes `@PostConstruct` (après construction) et `@PreDestroy` (avant destruction). Ou implémente `InitializingBean`, `DisposableBean`.

**Exercice 26.8** - Properties et Environment  
Externalise la configuration : fichier `application.properties`. Injecte avec `@Value("${property.name}")` ou `Environment.getProperty()`. Utilise `@PropertySource` pour charger.

**Exercice 26.9** - Profiles Spring  
Crée des beans conditionnels par environnement : `@Profile("dev")`, `@Profile("prod")`. Active avec `-Dspring.profiles.active=dev` ou `application.properties`.

**Exercice 26.10** - Application complète Spring Core  
Crée une app console Spring complète : plusieurs couches (Service, Repository), injection de dépendances, configuration properties, profiles, tests unitaires avec Spring Test.

---

### **Chapitre 27 — Spring Boot**

**Exercice 27.1** - Premier projet Spring Boot  
Crée un projet Spring Boot avec Spring Initializr : dépendances Web, DevTools. Crée `@SpringBootApplication` main class. Lance avec `mvn spring-boot:run`. Auto-configuration magique.

**Exercice 27.2** - Premier REST Controller  
Crée un `@RestController` avec `@GetMapping("/hello")` qui retourne "Hello World". Spring Boot configure automatiquement Tomcat embedded, JSON marshalling, etc.

**Exercice 27.3** - application.properties  
Configure l'app dans `application.properties` : `server.port`, `logging.level`, propriétés custom. Ou utilise `application.yml` (format YAML). Injecte avec `@Value` ou `@ConfigurationProperties`.

**Exercice 27.4** - @ConfigurationProperties  
Crée une classe de configuration type-safe : `@ConfigurationProperties(prefix="app")` avec fields et getters/setters. Spring mappe automatiquement depuis properties.

**Exercice 27.5** - Spring Boot DevTools  
Ajoute DevTools : restart automatique quand code change, LiveReload, configurations dev. Améliore productivité en développement.

**Exercice 27.6** - Actuator  
Ajoute `spring-boot-starter-actuator`. Accède aux endpoints : `/actuator/health`, `/actuator/metrics`, `/actuator/env`. Monitoring et métriques out-of-the-box.

**Exercice 27.7** - Data JPA  
Ajoute `spring-boot-starter-data-jpa` et H2 database. Crée une entité `@Entity`, un repository `extends JpaRepository`. Spring Boot configure DataSource, EntityManager automatiquement.

**Exercice 27.8** - REST API CRUD  
Crée une API REST complète : `@GetMapping` (list), `@GetMapping("/{id}")` (get), `@PostMapping` (create), `@PutMapping` (update), `@DeleteMapping` (delete). Utilise JPA repository.

**Exercice 27.9** - Exception handling  
Gère les erreurs avec `@ControllerAdvice` et `@ExceptionHandler`. Retourne des réponses JSON structurées avec codes HTTP appropriés. Centralise la gestion d'erreurs.

**Exercice 27.10** - Application Boot complète  
Crée une app complète : API REST, persistance JPA, validation avec `@Valid`, pagination, tri, filtrage, Swagger documentation avec SpringDoc, tests d'intégration.

---

### **Chapitre 28 — Spring Security**

**Exercice 28.1** - Security basique  
Ajoute `spring-boot-starter-security`. Spring Boot active automatiquement l'authentification HTTP Basic. User par défaut : "user", password dans les logs. Teste avec Postman.

**Exercice 28.2** - In-memory authentication  
Configure users en mémoire : `@Bean SecurityFilterChain` avec `http.authorizeHttpRequests()`, `.formLogin()`. Crée users avec `InMemoryUserDetailsManager`. Teste login.

**Exercice 28.3** - Database authentication  
Authentification depuis base : crée tables users/roles, implémente `UserDetailsService` qui charge depuis DB. Spring Security gère les mots de passe hashés (BCrypt).

**Exercice 28.4** - Password encoding  
Hash les mots de passe avec `BCryptPasswordEncoder`. Jamais stocker en clair. Configure : `@Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); }`.

**Exercice 28.5** - Authorization  
Configure les autorisations : `.requestMatchers("/admin/**").hasRole("ADMIN")`, `.requestMatchers("/user/**").hasRole("USER")`. Teste avec différents users/roles.

**Exercice 28.6** - Method security  
Active `@EnableMethodSecurity`. Utilise `@PreAuthorize("hasRole('ADMIN')")` sur méthodes, `@PostAuthorize`, `@Secured`. Sécurité au niveau service.

**Exercice 28.7** - JWT Authentication  
Implémente JWT : crée token au login, valide token dans filtre, stocke dans SecurityContext. Plus scalable que sessions pour API REST.

**Exercice 28.8** - OAuth2 Login  
Configure OAuth2 pour login avec Google/GitHub : `spring-boot-starter-oauth2-client`, configure dans properties (client-id, secret). Login social simplifié.

**Exercice 28.9** - CORS et CSRF  
Configure CORS : `.cors()` pour permettre requests cross-origin. Gère CSRF : désactive pour API REST stateless (`.csrf().disable()`), garde pour apps avec sessions.

**Exercice 28.10** - Application sécurisée complète  
Crée une app complète : authentification JWT, autorisation basée sur rôles, endpoints publics/protégés/admin, refresh tokens, logout, tests de sécurité.

---

### **Chapitre 29 — Hibernate et JPA**

**Exercice 29.1** - Première entité JPA  
Crée une entité : `@Entity class User { @Id @GeneratedValue Long id; String nom; }`. Configure persistence.xml ou use Spring Boot. EntityManager gère la persistance.

**Exercice 29.2** - CRUD avec EntityManager  
Utilise `EntityManager` : `.persist()` (insert), `.find()` (select), `.merge()` (update), `.remove()` (delete). Transactions avec `@Transactional`.

**Exercice 29.3** - Mapping annotations  
Explore : `@Table(name="...")`, `@Column(name="...", nullable=false, length=100)`, `@Temporal`, `@Enumerated`, `@Lob` (large objects). Configure précisément le mapping.

**Exercice 29.4** - Relations One-to-Many  
Crée relation : `@OneToMany` côté parent, `@ManyToOne` côté enfant. Exemple : User has many Orders. Configure `mappedBy`, `cascade`, `fetch`. Teste la navigation.

**Exercice 29.5** - Relations Many-to-Many  
Crée `@ManyToMany` avec table de jointure : Student <-> Course. Configure `@JoinTable`. Ajoute/supprime des associations. Gère la bidirectionnalité.

**Exercice 29.6** - JPQL queries  
Utilise JPQL (Java Persistence Query Language) : `entityManager.createQuery("SELECT u FROM User u WHERE u.age > :age")`. Plus orienté objet que SQL natif.

**Exercice 29.7** - Criteria API  
Utilise Criteria API pour requêtes type-safe : `CriteriaBuilder`, `CriteriaQuery`, `Root`, `Predicate`. Plus verbeux mais type-safe et composable. Bon pour requêtes dynamiques.

**Exercice 29.8** - Spring Data JPA  
Utilise Spring Data JPA : interface `extends JpaRepository<User, Long>`. Méthodes CRUD automatiques. Query methods : `findByNomAndAge`, `findByAgeGreaterThan`. Magique.

**Exercice 29.9** - @Query custom  
Custom queries dans repository : `@Query("SELECT u FROM User u WHERE u.email = ?1")`. Ou requêtes natives : `@Query(value="SELECT * FROM users", nativeQuery=true)`.

**Exercice 29.10** - Performance et caching  
Optimise : fetch LAZY vs EAGER, N+1 problem (solve avec JOIN FETCH), second-level cache (Ehcache), pagination avec `Pageable`. Profile avec Hibernate statistics.

---

### **Chapitre 30 — Microservices avec Spring Cloud**

**Exercice 30.1** - Premier microservice  
Crée un microservice simple Spring Boot : API REST indépendante, sa propre base de données, déployable séparément. Architecture microservices vs monolithique.

**Exercice 30.2** - Service discovery avec Eureka  
Configure Eureka Server : `@EnableEurekaServer`. Les microservices s'enregistrent : `@EnableEurekaClient`. Découverte automatique des services.

**Exercice 30.3** - API Gateway  
Configure Spring Cloud Gateway : routage des requêtes vers microservices, point d'entrée unique, load balancing. Filtre les requêtes, gère CORS, etc.

**Exercice 30.4** - Configuration centralisée  
Utilise Spring Cloud Config : serveur de configuration centralisé (Git backend), clients chargent leur config au démarrage. Change config sans rebuild.

**Exercice 30.5** - Load balancing  
Configure load balancing côté client avec Spring Cloud LoadBalancer (remplace Ribbon). Distribue les appels entre instances d'un service.

**Exercice 30.6** - Circuit breaker avec Resilience4j  
Implémente pattern Circuit Breaker : `@CircuitBreaker(name="service")`. Si service down, fallback automatique. Évite cascading failures.

**Exercice 30.7** - Distributed tracing  
Configure Spring Cloud Sleuth + Zipkin : trace les requêtes à travers microservices, correlation ID automatique, visualise dans Zipkin UI.

**Exercice 30.8** - Communication inter-services  
Appelle un service depuis un autre : `RestTemplate`, `WebClient` (réactif), ou `FeignClient` (déclaratif). Compare les approches.

**Exercice 30.9** - Message-driven avec RabbitMQ  
Communication asynchrone : configure Spring AMQP, envoie messages avec `RabbitTemplate`, consomme avec `@RabbitListener`. Découplage des services.

**Exercice 30.10** - Architecture microservices complète  
Crée 3+ microservices : service discovery, gateway, config server, 2-3 business services, circuit breaker, tracing. Architecture production-ready.

---

## [CALCUL] PARTIE 6 — Programmation Avancée et Performance

---

### **Chapitre 31 — Threads et Concurrence**

**Exercice 31.1** - Premier Thread  
Crée un thread : extends `Thread` et override `run()`, ou implémente `Runnable`. Lance avec `.start()`. Attends avec `.join()`. Compare les deux approches.

**Exercice 31.2** - Thread priorities et daemon  
Configure la priorité : `.setPriority(Thread.MAX_PRIORITY)`. Crée daemon threads : `.setDaemon(true)`. Les daemons s'arrêtent quand tous les non-daemons sont terminés.

**Exercice 31.3** - Synchronization  
Synchronise l'accès aux ressources partagées : `synchronized` method ou block. Sans synchro, observe les race conditions. Avec synchro, données cohérentes.

**Exercice 31.4** - Wait et Notify  
Utilise `.wait()`, `.notify()`, `.notifyAll()` pour la communication inter-threads. Pattern producer-consumer : producer notifie, consumer attend.

**Exercice 31.5** - Executors et Thread Pools  
Utilise `ExecutorService` : `Executors.newFixedThreadPool(4)`. Soumets des tâches avec `.submit()` ou `.execute()`. Plus propre que créer Thread manuellement.

**Exercice 31.6** - Callable et Future  
Utilise `Callable<T>` (retourne une valeur contrairement à Runnable). Soumets à ExecutorService, récupère `Future<T>`, obtiens résultat avec `.get()` (bloquant).

**Exercice 31.7** - Concurrent Collections  
Utilise collections thread-safe : `ConcurrentHashMap`, `CopyOnWriteArrayList`, `BlockingQueue`. Compare performance avec Collections.synchronizedXxx().

**Exercice 31.8** - Atomic variables  
Utilise `AtomicInteger`, `AtomicLong`, `AtomicReference`. Opérations atomiques sans synchronization : `.incrementAndGet()`, `.compareAndSet()`. Lock-free.

**Exercice 31.9** - Locks et Conditions  
Utilise `ReentrantLock` : plus flexible que synchronized. `Condition` pour await/signal. Try-lock avec timeout. Read-write locks pour optimiser lectures.

**Exercice 31.10** - Application concurrente complète  
Crée un web crawler multi-threadé : pool de threads, queue de URLs, synchronisation, évite visiter 2x même URL (ConcurrentHashMap), gère les erreurs.

---

### **Chapitre 32 — Programmation réactive avec Reactor**

**Exercice 32.1** - Premier Flux  
Crée un `Flux<Integer>` : `Flux.just(1, 2, 3, 4, 5)`. Subscribe et affiche : `.subscribe(System.out::println)`. Comprends les concepts : Publisher, Subscriber.

**Exercice 32.2** - Mono vs Flux  
`Mono` = 0 ou 1 élément, `Flux` = 0 à N éléments. Crée des exemples de chaque. Convertis : `mono.flux()`, `flux.next()`.

**Exercice 32.3** - Operators map et filter  
Transforme avec `.map(x -> x * 2)`, filtre avec `.filter(x -> x > 5)`. Chaîne plusieurs operators. Pipeline déclaratif comme Streams.

**Exercice 32.4** - FlatMap et merge  
Utilise `.flatMap()` pour transformer en Flux puis aplatir. Combine des Flux avec `.merge()`, `.concat()`, `.zip()`. Gère l'asynchrone.

**Exercice 32.5** - Error handling  
Gère les erreurs : `.onErrorReturn(defaultValue)`, `.onErrorResume(flux)`, `.doOnError()`. La propagation d'erreur arrête le flux.

**Exercice 32.6** - Backpressure  
Comprends la backpressure : consumer peut demander nombre d'éléments. Stratégies : `buffer()`, `onBackpressureDrop()`, `onBackpressureLatest()`.

**Exercice 32.7** - Schedulers  
Change le thread d'exécution : `.subscribeOn(Schedulers.parallel())` (où subscribe), `.publishOn(Schedulers.io())` (où downstream operators). Threading explicite.

**Exercice 32.8** - Hot vs Cold publishers  
Cold = recommence pour chaque subscriber (flux de fichier). Hot = broadcast aux subscribers (events). Convertis avec `.share()` ou `ConnectableFlux`.

**Exercice 32.9** - WebFlux REST  
Crée API REST réactive avec Spring WebFlux : retourne `Mono<User>` ou `Flux<User>`. Non-bloquant, scalable. Configure avec `@EnableWebFlux`.

**Exercice 32.10** - Application réactive complète  
Crée app réactive : WebFlux endpoints, reactive MongoDB ou R2DBC, WebClient pour appels externes non-bloquants. Tout le stack réactif.

---

### **Chapitre 33 — Performance et Optimisation**

**Exercice 33.1** - JMH Benchmarking  
Utilise JMH (Java Microbenchmark Harness) pour benchmarks précis. Mesure performance de différentes implémentations. Évite les pièges du benchmarking.

**Exercice 33.2** - Profiling avec VisualVM  
Utilise VisualVM pour profiler : CPU, mémoire, threads. Identifie les hotspots (méthodes qui consomment le plus). Connecte-toi à une app en cours.

**Exercice 33.3** - Memory leaks  
Crée volontairement un memory leak (collection qui grandit indéfiniment). Détecte avec profiler. Corrige. Utilise `jmap`,