Chapitre 17
17 - Exercices
> 40 exercices pratiques pour maîtriser Java moderne : des streams aux microservices
Chapitre 17 — Exercices : 40 exercices Java modernes
Mise en pratique intensive : de la manipulation de streams aux architectures microservices
Exercice 1 — Streams : Filter, Map, Reduce
Contexte : Vous disposez d'une liste de transactions bancaires. Calculez le solde total des transactions de type "CREDIT" dont le montant dépasse 100€.
record Transaction(String type, double amount, String category) {}
List<Transaction> transactions = List.of(
new Transaction("CREDIT", 150.0, "Salaire"),
new Transaction("DEBIT", 50.0, "Courses"),
new Transaction("CREDIT", 80.0, "Freelance"),
new Transaction("CREDIT", 200.0, "Vente")
);
Critères :
- Utiliser exclusivement l'API Stream (pas de boucle)
- Gérer le cas où la liste est vide
- Retourner un
OptionalDouble
Exercice 2 — Streams : FlatMap et groupingBy
Contexte : À partir d'une liste de commandes contenant plusieurs articles, regroupez les articles vendus par catégorie avec le total des quantités.
record Article(String name, String category, int quantity) {}
record Order(String id, List<Article> articles) {}
Attendu : Map<String, Integer> — catégorie → quantité totale
Exercice 3 — Optional : Chaînage et transformation
Contexte : Service de recherche d'utilisateur par email. Enchaînez les appels findByEmail, map to profile, flatMap to address.
Optional<User> findByEmail(String email);
Optional<Profile> getProfile(User user);
Optional<Address> getAddress(Profile profile);
// Retourner la ville ou "Unknown"
Contrainte : Un seul pipeline, pas de ifPresent ou isPresent.
Exercice 4 — Streams : Partitionnement et statistiques
Contexte : Partitionnez une liste d'employés entre ceux qui gagnent plus et moins de 50000€. Pour chaque groupe, calculez la moyenne, le min, le max, et le total.
Utilisez Collectors.partitioningBy et Collectors.summarizingDouble.
Exercice 5 — Streams : Custom Collector
Contexte : Implémentez un Collector personnalisé qui collecte les éléments en une String avec un séparateur, un préfixe et un suffixe (équivalent à Collectors.joining mais en mode custom).
static <T> Collector<T, ?, String> customJoining(
String delimiter, String prefix, String suffix
)
Exercice 6 — CompletableFuture : Appels parallèles
Contexte : Trois services HTTP indépendants (prix, stock, avis). Appelez-les en parallèle et combinez leurs résultats.
CompletableFuture<Price> fetchPrice(String productId);
CompletableFuture<Stock> fetchStock(String productId);
CompletableFuture<Review> fetchReviews(String productId);
Utilisez CompletableFuture.allOf puis combinez les résultats.
Exercice 7 — CompletableFuture : Timeout et fallback
Contexte : Appelez un service externe avec un timeout de 2 secondes. Si le délai est dépassé, retournez une valeur par défaut.
CompletableFuture<Product> fetchProduct(String id);
// Timeout 2s, fallback = Product.DEFAULT
Utilisez orTimeout (Java 9+) et exceptionally.
Exercice 8 — CompletableFuture : Pipeline asynchrone
Contexte : Enchaînez : validation → enrichissement → persist → notification. Chaque étape est asynchrone.
CompletableFuture<Order> validate(Order o);
CompletableFuture<Order> enrich(Order o);
CompletableFuture<Order> save(Order o);
CompletableFuture<Void> notify(Order o);
Utilisez thenCompose et thenAccept.
Exercice 9 — CompletableFuture : Rate Limiting
Contexte : Vous avez 100 URLs à télécharger. Limitez à 5 appels concurrents maximum.
// Utiliser un Executor avec un thread pool de taille 5
ExecutorService executor = Executors.newFixedThreadPool(5);
Exercice 10 — CompletableFuture : Composition conditionnelle
Contexte : Appelez un service de cache, si absent appelez le service distant. Avec gestion de fallback et retry (1 tentative).
CompletableFuture<Data> fromCache(String key);
CompletableFuture<Data> fromRemote(String key);
Exercice 11 — JPA : Entity Mapping avancé
Contexte : Créez un modèle JPA complet pour un système de e-commerce avec :
User(id, name, email, addresses)Address(street, city, zipCode, type: LIVRAISON/FACTURATION)Order(id, date, status, user, items)OrderItem(product, quantity, unitPrice)Product(id, name, price, category)
Utilisez @OneToMany, @ManyToOne, @ElementCollection, @Enumerated, @Embeddable.
Exercice 12 — JPA : Criteria API dynamique
Contexte : Implémentez une recherche dynamique de produits avec des filtres optionnels : nom, catégorie, prixMin, prixMax, enStock.
List<Product> search(String name, String category,
Double minPrice, Double maxPrice, Boolean inStock);
Utilisez CriteriaBuilder, Predicate, Root.
Exercice 13 — JPA : Pagination et tri
Contexte : Implémentez une méthode Page<Product> avec tri par nom, prix ou date d'ajout. Support des filtres.
Page<Product> getProducts(ProductFilter filter, Pageable pageable);
Exercice 14 — JPA : Transaction et Optimistic Locking
Contexte : Implémentez une réservation de billets avec contrôle de concurrence. Utilisez @Version et @Transactional.
Gérez l'exception OptimisticLockException avec un retry.
Exercice 15 — Spring Boot REST : CRUD complet
Contexte : Créez un contrôleur REST pour Product avec :
GET /api/products— liste avec paginationGET /api/products/{id}— détailPOST /api/products— créationPUT /api/products/{id}— mise à jourDELETE /api/products/{id}— suppression soft
Utilisez @RestController, @Valid, ResponseEntity, @ExceptionHandler.
Exercice 16 — Validation avancée
Contexte : Créez un DTO CreateOrderRequest avec validation :
@NotBlankuserId@NotEmptyitems (min 1)@Positivechaque quantité et prix@FuturedeliveryDate optionnelle- Validation cross-champ : si livraison, adresse requise
Exercice 17 — Gestion globale des exceptions
Contexte : Créez un @RestControllerAdvice qui gère :
MethodArgumentNotValidException→ 400 avec détailsEntityNotFoundException→ 404DataIntegrityViolationException→ 409GenericException→ 500 (log + correlationId)
Exercice 18 — HATEOAS avec Spring Boot
Contexte : Ajoutez des liens HATEOAS à l'API Products :
- Self link sur chaque ressource
- Lien vers la collection
- Lien vers les actions possibles (update, delete)
- Pagination links (first, prev, next, last)
Exercice 19 — JUnit 5 : Parametrized Tests
Contexte : Testez une méthode de validation ISBN avec différents cas :
boolean isValidISBN(String isbn);
Utilisez @CsvSource, @ValueSource, @MethodSource pour 20+ cas.
Exercice 20 — Mockito : Mock avancé
Contexte : Testez un OrderService qui dépend de PaymentGateway, InventoryService, NotificationService.
- Vérifiez les interactions
- Utilisez
ArgumentCaptor,doThrow,verify - Testez le cas où le paiement échoue → rollback
Exercice 21 — Testcontainers : PostgreSQL
Contexte : Testez un UserRepository avec une vraie base PostgreSQL via Testcontainers.
@Container
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16");
Testez CRUD, contraintes d'unicité, requêtes personnalisées.
Exercice 22 — Testcontainers : Kafka
Contexte : Testez un producer/consumer Kafka avec Testcontainers.
@Container
static KafkaContainer kafka = new KafkaContainer(
DockerImageName.parse("confluentinc/cp-kafka:7.6.0")
);
Exercice 23 — ArchUnit : Tests d'architecture
Contexte : Écrivez des tests ArchUnit qui vérifient :
- Les services ne dépendent pas des contrôleurs
- Les repositories sont des interfaces
- Les packages respectent la structure hexagonale
- Aucune dépendance cyclique
Exercice 24 — Feign Client : Appel inter-service
Contexte : Créez un client Feign pour appeler un service de catalogue depuis un service de commande.
@FeignClient(name = "catalog-service")
interface CatalogClient {
@GetMapping("/api/products/{id}")
Product getProduct(@PathVariable String id);
}
Avec configuration des timeouts, retry et fallback.
Exercice 25 — Resilience4j : Circuit Breaker
Contexte : Ajoutez un Circuit Breaker sur l'appel au service de paiement. Configurez :
- Seuil d'échec : 50%
- Fenêtre : 10 appels
- Délai d'attente : 5 secondes
- Fallback : paiement en attente (PENDING)
Exercice 26 — Spring Cloud Config : Configuration externalisée
Contexte : Créez un service config-server et un client qui lit sa configuration depuis un dépôt Git.
# application.yml dans le repo config
database:
url: jdbc:postgresql://localhost:5432/mydb
pool:
max-size: 20
Exercice 27 — Service Discovery : Eureka
Contexte : Configurez un service registry Eureka et deux microservices qui s'enregistrent et se découvrent mutuellement.
Exercice 28 — API Gateway : Spring Cloud Gateway
Contexte : Configurez une gateway avec :
- Routage vers les services
- Rate limiting (50 req/s par client)
- Filtre JWT pour valider les tokens
- Logging des requêtes
Exercice 29 — JFR : Flight Recorder
Contexte : Lancez une application Spring Boot avec JFR, déclenchez un dump, puis analysez :
- GC events, CPU sampling, allocation profiler
- Thread locks, IO waits
- Méthodes les plus chaudes (hot methods)
Commandes : jcmd <pid> JFR.start, JFR.dump, JFR.stop
Exercice 30 — GC Tuning : G1 / ZGC
Contexte : Une application de 8 Go de heap avec des pics de latence. Configurez :
- G1GC :
-XX:G1HeapRegionSize=4m -XX:MaxGCPauseMillis=50 - Ou ZGC :
-XX:+UseZGC -XX:ConcGCThreads=4
Testez avec un benchmark et comparez les métriques.
Exercice 31 — Profiling : Async Profiler
Contexte : Utilisez Async Profiler (ou IntelliJ profiler) pour identifier un goulot d'étranglement CPU dans une application qui traite des fichiers CSV.
Exercice 32 — Memory Analysis : Heap Dump
Contexte : Générez un heap dump d'une application qui a une fuite mémoire. Analysez avec Eclipse MAT ou IntelliJ :
- Identify the leak suspect
- Dominator tree
- GC roots
Exercice 33 — JVM Tuning : Flags et diagnostics
Contexte : Optimisez les flags JVM pour une application Spring Boot avec :
- Heap : 2 Go initial, 4 Go max
- Metaspace : 256 Mo
- Stack : 512 Ko par thread
- GC Logging avec rotation
- JMX exposé
Exercice 34 — Spring Security : Configuration basique
Contexte : Configurez Spring Security avec :
- Login form et JWT token
- Deux rôles : USER et ADMIN
- Endpoints protégés :
/api/admin/**(ADMIN only) /api/public/**accessible sans authentification
Exercice 35 — JWT : Generation et validation
Contexte : Implémentez un service JWT complet :
String generateToken(UserDetails user);
Claims validateToken(String token);
boolean isTokenExpired(String token);
String refreshToken(String token);
Utilisez jjwt (io.jsonwebtoken).
Exercice 36 — OAuth2 : Keycloak integration
Contexte : Intégrez Keycloak comme fournisseur OAuth2 avec Spring Security :
- Authorization Code flow
- Resource Server avec JWT
- Roles mapping (realm → application)
Exercice 37 — Method Security
Contexte : Sécurisez les méthodes avec @PreAuthorize, @PostAuthorize, @Secured :
- Un utilisateur ne peut modifier que son propre profil
- Un ADMIN peut tout modifier
- Vérification basée sur l'ID de l'utilisateur connecté
Exercice 38 — CSRF et CORS
Contexte : Configurez CSRF et CORS pour une application Angular front-end :
- CSRF : activé avec CookieCsrfTokenRepository
- CORS : autoriser origin
http://localhost:4200 - Méthodes autorisées : GET, POST, PUT, DELETE, OPTIONS
Exercice 39 — Mini-projet : API de réservation
Contexte : Créez une API REST complète pour un système de réservation :
- Créneaux horaires (disponible/réservé)
- Réservation utilisateur avec confirmation email
- Annulation avec pénalité si < 24h
- Reporting (réservations par jour/semaine/mois)
- Tests complets (unitaires + intégration)
Stack : Spring Boot 3.2+, PostgreSQL 16, Testcontainers, JUnit 5, Mockito
Exercice 40 — Mini-projet : Pipeline de traitement
Contexte : Implémentez un pipeline ETL qui :
- Lit un fichier CSV de commandes (100k+ lignes)
- Valide et transforme avec Streams
- Enrichit avec des appels parallèles (CompletableFuture)
- Persiste en base avec JPA batch insert
- Notifie via Kafka
- Archive le fichier traité
Avec monitoring JFR et tests de performance.
Récapitulatif des compétences
| # | Compétence | Niveau |
|---|---|---|
| 1-5 | Streams & Optional | Intermédiaire |
| 6-10 | CompletableFuture | Intermédiaire |
| 11-14 | JPA/Hibernate | Avancé |
| 15-18 | Spring Boot REST | Intermédiaire |
| 19-23 | Testing | Avancé |
| 24-28 | Microservices | Avancé |
| 29-33 | Performance | Expert |
| 34-38 | Security | Avancé |
| 39-40 | Projets | Expert |
Barème indicatif
- 30+ exercices réussis : Prêt pour poste Senior
- 20-29 : Développeur confirmé
- 10-19 : Débutant à intermédiaire
- < 10 : Réviser les fondamentaux