Aller au contenu

SEMAINE 1 - JOUR 3 : TYPES, VARIABLES, MÉMOIRE ET CALCULS MÉTIER EN JAVA

Formation Java / Spring Boot pour développeurs COBOL


types java


Objectifs pédagogiques

À l’issue de cette troisième journée (qui débordera sur le Jour 4), vous serez être capable de :

Cette journée conditionne la compréhension de tout ce qui suivra (POO, collections, JPA) de la semaine suivante.


Mise en contexte (COBOL → Java)

En COBOL, vous avez une vision très claire des données :

En Java :

Cette différence est l’une des sources majeures de bugs pour les débutants Java. Nous allons donc l’expliquer lentement, avec des analogies COBOL puis nous pourrons pas la suite ne présenter que du code Java.


Première approche

J’ai conçu le cours de la manière suivante :

Java Partie 1 - Sans Cobol

Dans ce cours, nous allons voir les bases de la syntaxe en Java

Java partie 2 - avec Cobol

Qu’est-ce qu’une variable en Java ?

Vous le savez, une variable Java se caractérise par :

Syntaxe générale : type nomDeVariable;

int nombreDeJourFormation;

ou directement avec une valeur : type nomDeVariable = valeur;

int nombreDeJourFormation = 30;

Comparaison directe COBOL ↔ Java (variables simples)

En Cobol, on a des niveaux de données “ordonnées” de manière séquentielle, des groupes de données, des variables indépendantes et l’utilisation de l’indentation. Cela dans le but de représenter des structures de données complexes. En Java, nous sommes dans un univers objet avec des variables (attributs) et des objets issus de classes. On utilise aussi l’indentation pour une meilleure lisibilité du code, mais pas de notion de niveaux, .

En Cobol :

01 SOLDE.
   05 SOLDE-COMPTE      PIC 9(7)V99.
   05 DATE-MAJ.
      10 ANNE-MAJ       PIC 9(4).
      10 MOIS-MAJ       PIC 9(2).
      10 JOUR-MAJ       PIC 9(2).

Soit :

En Java (première approche) en reprenant le code en Cobol comme exemple.

Ne tenez pas compte du mot-clé private pour le moment !

public class Client {
    private String idClient;        // PIC X(10)
    private String nom;             // PIC X(50)
    private double soldeCompte;     // 05 SOLDE-COMPTE  PIC 9(7)V99 (équivalent à un double)
    private DateMaj dateMaj;        // 05 DATE-MAJ.
    ...
}
// autre classe dans un autre fichier Java pour la date de mise à jour (il exsite des classes spécifiques)
    public class DateMaj {
        private int annee;        // PIC 9(4)
        private int mois;         // PIC 9(2)
        private int jour;         // PIC 9(2)
    }
    ...

Attention : Le type double ne garantit pas la précision décimale.

Les types primitifs en Java et l’équivalent en Cobol

Les types primitifs représentent des valeurs simples, stockées directement en mémoire (Stack ou pile).

Principaux types :

Type Java Description Équivalent conceptuel COBOL
int entier PIC 9
long entier long PIC 9 (grande taille)
double décimal approximatif NON recommandé en finance
boolean vrai/faux condition
char caractère PIC X(1)

Exemple :

int nombreOperations = 5;
boolean compteActif = true;

Type String : une fausse simplicité

En COBOL :

05 NOM-CLIENT PIC X(30).

En Java :

String nomClient;
//ou avec constructeur
String nomClient = new String();

String n’est pas un type primitif, c’est un objet manipulé par référence, mais Java masque cette complexité pour en simplifier l’usage. C’est pour cette raison que l’on peut lui affecter une valeur de 2 manières différentes.

String nomClient == "Dubosc";
//ou avec constructeur
String nomClient = new String("Dubosc");

Valeur vs Référence (notion fondamentale)

Types primitifs = passage par valeur

int a = 10;
int b = a;  // Copie de la valeur de a dans b
b = 20;     // Modifie seulement b

Résultat :

Explication :

Objets = passage par référence

Pour bien illustrer que Java passe les références par valeur, utilisons un objet mutable (comme un tableau ou une classe personnalisée que nous verrons ultérieurement) :

Avec un tableau (mutable)

int[] tableau1 = {1, 2, 3};
int[] tableau2 = tableau1;  // Copie de la référence
tableau2[0] = 99;            // Modifie le CONTENU de l'objet pointé

System.out.println(tableau1[0]);  // Affiche 99
System.out.println(tableau2[0]);  // Affiche 99

Résultat :

Mais attention : Si on fait tableau2 = new int[]{4, 5, 6};, tableau1 reste inchangé (car on change la référence de tableau2, pas le contenu de l’objet original).

Schéma mémoire :

tableau1 ----> [99, 2, 3] (adresse 0x300)
tableau2 ----> [99, 2, 3] (même adresse 0x300)

Avec une classe personnalisée (plus facile à comprendre)

class Personne {
    String nom;
    Personne(String nom) { this.nom = nom; }
}

public class Main {
    public static void main(String[] args) {
        Personne p1 = new Personne("Alicia");
        Personne p2 = p1;          // Copie de la référence
        p2.nom = "Joachim";        // Modifie l'objet pointé par p1 et p2

        System.out.println(p1.nom);  // affiche "Joachim"
        System.out.println(p2.nom);  // affiche "Joachim"
    }
}

Résultat :

Mais si on fait p2 = new Personne("Agnès");, p1 reste inchangé (car on change la référence de p2).

Schéma mémoire :

Avant p2.nom = "Joachim":
p1 ----> Personne("Alicia") (adresse 0x400)
p2 ----> Personne("Alicia") (même adresse 0x400)

Après p2.nom = "Joachim":
p1 ----> Personne("Joachim") (0x400)
p2 ----> Personne("Joachim") (0x400)

Nous pourrions aussi écrire un exemple avec des objets String mais comme String est IMMUABLE, toute affectation est une création d’un nouvel objet et par conséquent, une référence différente. En Java, une variable objet contient une adresse, pas la donnée elle-même.

Conclusion (valeur/référence)

Résumé sous forme de code (à tester):

// passage par valeur (primitif)
int x = 5;
int y = x;  // y est une copie de x
y = 10;     // x reste 5

System.out.println("x = "+x);
System.out.println("y = "+y);

// passage par valeur (référence à un objet immuable)
String a = "Bonjour";
String b = a;       // b est une copie de la référence de a
System.out.println("b = a donc b = "+b);
b = "Au revoir";    // b pointe vers un nouvel objet, a reste "Bonjour"

System.out.println("a = "+a);
System.out.println("b = Au revoir donc b = "+b);

// passage par valeur (référence à un objet mutable)
int[] t1 = {1, 2, 3};
int[] t2 = t1;  // t2 est une copie de la référence de t1
t2[0] = 99;       // Modifie l'objet pointé par t1 et t2 en affectant 99 à la place de 1
// t1 est maintenant {99, 2, 3}
System.out.println("t1 = "+t1); // on voit la référence de l'objet (pas le contenu)
System.out.println("t2 = "+t2); // on voit que la référence de l'objet est la même (idem)

Quelques explications sur la gestion de la mémoire…

Liste de travaux pratiques

Pourquoi double est dangereux en finance

Test simple :

double a = 0.1;
double b = 0.2;
System.out.println(a + b);

Résultat affiché :

0.30000000000000004

Ce comportement est normal pour l’informatique binaire, mais inacceptable en contexte bancaire !

BigDecimal : le bon type financier en Java

BigDecimal permet :

Exemple :

import java.math.BigDecimal;

BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal resultat = a.add(b);

Résultat :

0.3

Règles d’or BigDecimal

Lecture de données depuis la console

Pour interagir avec l’utilisateur, on utilise la classe Scanner :

import java.util.Scanner;

Scanner scanner = new Scanner(System.in);
System.out.print("Entrez le solde initial : ");
String saisie = scanner.nextLine();

// Conversion en BigDecimal
BigDecimal solde = new BigDecimal(saisie);

Comparaison COBOL ↔ Java (tableaux synthétiques)

Types numériques

COBOL Java Commentaire
PIC 9(7)V99 BigDecimal équivalent fonctionnel
PIC 9 int / long attention à la taille
calcul exact BigDecimal jamais double

Démonstrations guidées

Démo 1 – Calcul de solde simple (Java pur)

Objectif :

simuler un calcul COBOL en Java

BigDecimal solde = new BigDecimal("1000.00");
BigDecimal debit = new BigDecimal("200.50");
BigDecimal credit = new BigDecimal("150.00");

solde = solde.subtract(debit);
solde = solde.add(credit);

System.out.println("Solde final : " + solde);

Démo 2 – Lecture utilisateur + calcul

Scanner scanner = new Scanner(System.in);

System.out.print("Solde initial : ");
BigDecimal solde = new BigDecimal(scanner.nextLine());

System.out.print("Montant débit : ");
BigDecimal debit = new BigDecimal(scanner.nextLine());

solde = solde.subtract(debit);

System.out.println("Nouveau solde : " + solde);

Travaux pratiques – JOUR 3

TP 1 – Calcul de solde bancaire simple

Objectif : reproduire un traitement COBOL simple en Java

Consignes :

TP 2 – Comparaison double vs BigDecimal

Objectif : Constater concrètement le problème de précision

Consignes :

Comparer les résultats

TP 3 – Mini-contrôle métier

Objectif : introduire une règle métier simple

Consigne : si le solde final est négatif, afficher : “ATTENTION : COMPTE À DÉCOUVERT”

Corrections

Corrigé TP 1 – Calcul de solde

import java.math.BigDecimal;
import java.util.Scanner;

public class CalculSolde {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("Solde initial : ");
        BigDecimal solde = new BigDecimal(scanner.nextLine());

        System.out.print("Débit : ");
        BigDecimal debit = new BigDecimal(scanner.nextLine());

        System.out.print("Crédit : ");
        BigDecimal credit = new BigDecimal(scanner.nextLine());

        solde = solde.subtract(debit);
        solde = solde.add(credit);

        System.out.println("Solde final : " + solde);
    }
}

Points d’attention :

Corrigé TP 2 – Comparaison précision

double a = 0.1;
double b = 0.2;
System.out.println(a + b);

BigDecimal x = new BigDecimal("0.1");
BigDecimal y = new BigDecimal("0.2");
System.out.println(x.add(y));

Conclusion :

Corrigé TP 3 – Contrôle découvert

if (solde.compareTo(BigDecimal.ZERO) < 0) {
    System.out.println("ATTENTION : COMPTE À DÉCOUVERT");
}

Erreurs fréquentes

Avancement du TP fil rouge bancaire (BankLite)

Aujourd’hui, vous avez posé les bases métier :

Décision d’architecture progressive :

Synthèse de la journée

Vous savez :

Préparation du Jour 4

On abordera :