Aller au contenu

Semaine 2 : JOUR 4 - GESTION DES EXCEPTIONS & INTRODUCTION DOUCE À LA PROGRAMMATION FONCTIONNELLE (STREAMS)

Programmation fonctionnelle

Formation Java / Spring Boot pour développeurs COBOL


Objectifs pédagogiques

À l’issue de cette journée, vous sevez capable de :


Mise en contexte (COBOL → Java)

En COBOL : la gestion des erreurs

Classiquement, vous utilisez :

Exemple COBOL :

PERFORM DEBIT-COMPTE
IF CODE-RETOUR NOT = 0
    DISPLAY "ERREUR DEBIT"
    GO TO FIN-PROGRAMME
END-IF

Problèmes :


Cours

Découvrez les bases de la Programmation fonctionnelle & Lambdas

Découvrez comment fonctionne les Exceptions (version allégée)

Découvrez comment fonctionne les Exceptions (verion approfondie)

Démonstration

Reprendre les TP déjà réalisé et intégrer les nouveaux concepts.

Java : une philosophie différente

En Java :


Qu’est-ce qu’une exception ?

Une exception est :


Exemple simple

throw new IllegalArgumentException("Montant invalide");

Analogie COBOL

COBOL Java
CODE-RETOUR Exception
IF CODE ≠ 0 try / catch
GO TO ERREUR propagation automatique
DISPLAY MESSAGE message d’exception

En Java, on ne teste pas systématiquement, on laisse l’erreur remonter.


try / catch : intercepter une exception

Syntaxe

try {
    // code à risque
} catch (Exception e) {
    // traitement de l’erreur
}

Exemple métier bancaire

try {
    compte.debiter(new BigDecimal("2000"));
} catch (IllegalStateException e) {
    System.out.println("Débit refusé : " + e.getMessage());
}

Où lancer une exception ?

Une exception se lance là où l’erreur est détectée, pas là où elle est affichée.

if (solde < 0) {
    System.out.println("Erreur");
}
if (solde.compareTo(montant) < 0) {
    throw new IllegalStateException("Solde insuffisant");
}

Exceptions métier contre exceptions techniques

Exceptions techniques


Exceptions métier (les plus importantes)

font partie du métier, pas de la technique.


Créer sa propre exception métier

Exemple : DebitInterditException

public class DebitInterditException extends RuntimeException {

    public DebitInterditException(String message) {
        super(message);
    }
}

Utilisation :

throw new DebitInterditException("Découvert dépassé");

Lecture d’une stacktrace (sans panique)

Exemple :

Exception in thread "main" java.lang.IllegalStateException: Solde insuffisant
    at CompteEpargne.debiter(CompteEpargne.java:25)
    at Main.main(Main.java:10)

Lecture guidée :

  1. type d’erreur
  2. message
  3. méthode fautive
  4. ligne précise
  5. chemin d’appel

Ce n’est pas un message obscur, c’est un rapport d’enquête.


PAUSE CONCEPTUELLE

Pourquoi parler de Streams maintenant ?

Parce que :

Les Streams ne remplacent pas la POO, ils la rendent plus expressive.


Approche impérative (ce que vous connaissez)

int compteur = 0;

for (Compte c : comptes) {
    if (c.getSolde().compareTo(BigDecimal.ZERO) < 0) {
        compteur++;
    }
}

Lisible, mais :


Première approche fonctionnelle (doucement)

long nbDecouverts = comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) < 0)
    .count();

Comprendre ce qu’est un Stream

Un Stream, c’est :

Comparable à “Je prends la liste, je filtre, je compte”


filter – garder ce qui nous intéresse

comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) < 0)

Equivalent à IF condition, mais exprimé une fois pour toutes.


map – transformer les données

Exemple : récupérer les soldes

comptes.stream()
    .map(c -> c.getSolde())

Résultat :


forEach – agir sur chaque élément

comptes.stream()
    .forEach(c -> System.out.println(c.getSolde()));

forEach est une action finale. Après, le Stream est terminé.


collect – reconstruire une collection

List<Compte> comptesADecouvert = comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) < 0)
    .collect(Collectors.toList());

Transformation claire et aucun effet de bord.


Comparaison impératif vs fonctionnel

Impératif Fonctionnel
for / if filter
compteur count
liste temporaire collect
code long code expressif

On ne remplace pas tout, on choisit ce qui est plus lisible.


Démonstrations guidées (métier bancaire)

Démo 1 – Afficher tous les soldes négatifs

comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) < 0)
    .forEach(c -> System.out.println(c.getSolde()));

Démo 2 – Récupérer les numéros de comptes en découvert

List<String> numeros = comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) < 0)
    .map(c -> c.getNumero())
    .collect(Collectors.toList());

Travaux pratiques

TP 1 – Exceptions métier

Consignes :


TP 2 – Streams simples

Consignes :

  1. Compter les comptes créditeurs
  2. Compter les comptes à découvert
  3. Afficher tous les soldes

TP 3 – Comparaison impératif / fonctionnel

Consignes :


Corrigés (extraits clés)

Compter avec Stream

long nbCrediteurs = comptes.stream()
    .filter(c -> c.getSolde().compareTo(BigDecimal.ZERO) > 0)
    .count();

Section spéciale – Erreurs fréquentes

  1. Mettre toute la logique dans le catch
  2. Attraper Exception partout
  3. Utiliser les exceptions comme des if
  4. Avoir peur des stacktraces
  5. Penser que Streams = magie
  6. Utiliser Streams pour des traitements simples
  7. Modifier les objets dans map
  8. Oublier que Stream est à usage unique
  9. Mélanger logique métier et affichage
  10. Dire “c’est trop compliqué” (avant de l’avoir pratiqué)

Avancement du TP fil rouge bancaire (BankLite)

Aujourd’hui, vous avez :

Décisions structurantes :


Synthèse de la journée

Vous savez maintenant :