Structures de Contrôle en Java : Guide Complet

Maîtrisez les structures conditionnelles Java pour contrôler le flux d'exécution de vos programmes

Qu'est-ce qu'une structure de contrôle en Java ?

Les structures de contrôle (control structures) permettent de contrôler le flux d'exécution (execution flow) d'un programme Java. Elles déterminent quelles instructions seront exécutées en fonction de conditions (conditions) spécifiques. Sans ces structures, le code s'exécuterait toujours de manière linéaire, de la première à la dernière ligne.

Le langage Java propose plusieurs types de structures de contrôle : les instructions conditionnelles (if, else, switch), les boucles (for, while, do-while) et les instructions de branchement (break, continue, return). Ce guide se concentre sur les structures conditionnelles, essentielles pour tout développeur Java.

Comprendre et maîtriser les structures de contrôle est fondamental pour écrire des programmes dynamiques et interactifs. Elles vous permettent de prendre des décisions dans votre code, de valider des données (data), de gérer des erreurs (errors) et de créer une logique métier complexe.

L'instruction if en Java

L'instruction if est la structure conditionnelle de base en Java. Elle permet d'exécuter un bloc de code uniquement si une condition (boolean expression) est vraie (true). Si la condition est fausse (false), le bloc est ignoré.

Syntaxe de base

// Syntaxe de l'instruction if
if (condition) {
    // Code exécuté si la condition est vraie
}

// Exemple simple
int age = 20;

if (age >= 18) {
    System.out.println("Vous êtes majeur");
}

La condition entre parenthèses doit être une expression booléenne qui retourne true ou false. Les accolades {} délimitent le bloc de code à exécuter. Si le bloc ne contient qu'une seule instruction, les accolades sont optionnelles, mais il est recommandé de toujours les utiliser pour la lisibilité.

Exemples pratiques de if

public class ExemplesIf {
    public static void main(String[] args) {
        // Vérifier la majorité
        int age = 25;
        if (age >= 18) {
            System.out.println("Accès autorisé");
        }

        // Vérifier un mot de passe
        String motDePasse = "secret123";
        if (motDePasse.equals("secret123")) {
            System.out.println("Connexion réussie");
        }

        // Vérifier si un nombre est positif
        int nombre = 42;
        if (nombre > 0) {
            System.out.println("Le nombre est positif");
        }

        // Vérifier si une valeur n'est pas nulle
        String nom = "Alice";
        if (nom != null) {
            System.out.println("Bonjour " + nom);
        }

        // Conditions multiples avec &&
        boolean permis = true;
        if (age >= 18 && permis) {
            System.out.println("Peut conduire");
        }

        // Conditions alternatives avec ||
        boolean weekend = true;
        boolean vacances = false;
        if (weekend || vacances) {
            System.out.println("Jour de repos");
        }
    }
}

Bonne pratique : Utilisez toujours les accolades {} même pour une seule instruction. Cela évite les erreurs lors de l'ajout de code ultérieur et améliore la lisibilité.

L'instruction if-else en Java

L'instruction if-else permet d'exécuter un bloc de code si la condition est vraie, et un autre bloc si elle est fausse. C'est un choix binaire entre deux alternatives.

// Syntaxe if-else
if (condition) {
    // Code si condition vraie
} else {
    // Code si condition fausse
}

// Exemple
int age = 16;

if (age >= 18) {
    System.out.println("Vous êtes majeur");
} else {
    System.out.println("Vous êtes mineur");
}

Exemples pratiques de if-else

public class ExemplesIfElse {
    public static void main(String[] args) {
        // Vérifier un nombre pair ou impair
        int nombre = 7;
        if (nombre % 2 == 0) {
            System.out.println(nombre + " est pair");
        } else {
            System.out.println(nombre + " est impair");
        }

        // Vérifier le signe d'un nombre
        int valeur = -5;
        if (valeur >= 0) {
            System.out.println("Positif ou nul");
        } else {
            System.out.println("Négatif");
        }

        // Authentification
        String username = "admin";
        String password = "pass123";

        if (username.equals("admin") && password.equals("pass123")) {
            System.out.println("Connexion réussie");
        } else {
            System.out.println("Identifiants incorrects");
        }

        // Vérifier une limite
        int score = 75;
        if (score >= 50) {
            System.out.println("Examen réussi");
        } else {
            System.out.println("Examen échoué");
        }
    }
}

L'instruction else-if en Java

L'instruction else-if permet de tester plusieurs conditions successives. Elle est utilisée quand vous avez plus de deux alternatives possibles. Dès qu'une condition est vraie, le bloc correspondant est exécuté et les autres conditions ne sont pas testées.

// Syntaxe else-if
if (condition1) {
    // Code si condition1 vraie
} else if (condition2) {
    // Code si condition2 vraie
} else if (condition3) {
    // Code si condition3 vraie
} else {
    // Code si aucune condition n'est vraie
}

Exemples pratiques de else-if

public class ExemplesElseIf {
    public static void main(String[] args) {
        // Système de notation
        int note = 85;

        if (note >= 90) {
            System.out.println("Mention: Excellent");
        } else if (note >= 80) {
            System.out.println("Mention: Très bien");
        } else if (note >= 70) {
            System.out.println("Mention: Bien");
        } else if (note >= 60) {
            System.out.println("Mention: Assez bien");
        } else if (note >= 50) {
            System.out.println("Mention: Passable");
        } else {
            System.out.println("Mention: Insuffisant");
        }

        // Catégories d'âge
        int age = 35;

        if (age < 13) {
            System.out.println("Enfant");
        } else if (age < 18) {
            System.out.println("Adolescent");
        } else if (age < 60) {
            System.out.println("Adulte");
        } else {
            System.out.println("Senior");
        }

        // Prix selon la quantité
        int quantite = 150;
        double prixUnitaire = 10.0;
        double remise = 0.0;

        if (quantite >= 100) {
            remise = 0.20;  // 20% de remise
            System.out.println("Remise de 20%");
        } else if (quantite >= 50) {
            remise = 0.10;  // 10% de remise
            System.out.println("Remise de 10%");
        } else if (quantite >= 10) {
            remise = 0.05;  // 5% de remise
            System.out.println("Remise de 5%");
        } else {
            System.out.println("Pas de remise");
        }

        double total = quantite * prixUnitaire * (1 - remise);
        System.out.println("Total: " + total + "€");
    }
}

L'instruction switch en Java

L'instruction switch permet de tester une variable contre plusieurs valeurs possibles. C'est une alternative plus lisible à une série de if-else-if quand vous comparez une même variable à différentes valeurs constantes. Le switch fonctionne avec les types int, byte, short, char, String et les enums.

Syntaxe du switch

// Syntaxe switch
switch (variable) {
    case valeur1:
        // Code si variable == valeur1
        break;
    case valeur2:
        // Code si variable == valeur2
        break;
    case valeur3:
        // Code si variable == valeur3
        break;
    default:
        // Code si aucun case ne correspond
        break;
}

Le mot-clé break est crucial : il permet de sortir du switch après l'exécution d'un case. Sans break, l'exécution continue dans les case suivants (fall-through).

Exemples pratiques de switch

public class ExemplesSwitch {
    public static void main(String[] args) {
        // Jours de la semaine
        int jour = 3;

        switch (jour) {
            case 1:
                System.out.println("Lundi");
                break;
            case 2:
                System.out.println("Mardi");
                break;
            case 3:
                System.out.println("Mercredi");
                break;
            case 4:
                System.out.println("Jeudi");
                break;
            case 5:
                System.out.println("Vendredi");
                break;
            case 6:
                System.out.println("Samedi");
                break;
            case 7:
                System.out.println("Dimanche");
                break;
            default:
                System.out.println("Jour invalide");
                break;
        }

        // Menu avec String
        String choix = "ajouter";

        switch (choix) {
            case "ajouter":
                System.out.println("Ajout d'un élément");
                break;
            case "modifier":
                System.out.println("Modification d'un élément");
                break;
            case "supprimer":
                System.out.println("Suppression d'un élément");
                break;
            case "quitter":
                System.out.println("Au revoir");
                break;
            default:
                System.out.println("Commande inconnue");
                break;
        }

        // Grouper plusieurs cas
        int mois = 4;

        switch (mois) {
            case 12:
            case 1:
            case 2:
                System.out.println("Hiver");
                break;
            case 3:
            case 4:
            case 5:
                System.out.println("Printemps");
                break;
            case 6:
            case 7:
            case 8:
                System.out.println("Été");
                break;
            case 9:
            case 10:
            case 11:
                System.out.println("Automne");
                break;
            default:
                System.out.println("Mois invalide");
                break;
        }
    }
}

Switch expressions (Java 14+)

Depuis Java 14, vous pouvez utiliser les switch expressions qui offrent une syntaxe plus concise et retournent une valeur. Cette nouvelle forme utilise l'opérateur -> et ne nécessite pas de break.

public class SwitchExpression {
    public static void main(String[] args) {
        // Ancienne syntaxe
        int jour = 3;
        String nomJour = "";

        switch (jour) {
            case 1:
                nomJour = "Lundi";
                break;
            case 2:
                nomJour = "Mardi";
                break;
            case 3:
                nomJour = "Mercredi";
                break;
            default:
                nomJour = "Inconnu";
                break;
        }

        // Nouvelle syntaxe (Java 14+)
        String nomJour2 = switch (jour) {
            case 1 -> "Lundi";
            case 2 -> "Mardi";
            case 3 -> "Mercredi";
            case 4 -> "Jeudi";
            case 5 -> "Vendredi";
            case 6 -> "Samedi";
            case 7 -> "Dimanche";
            default -> "Inconnu";
        };

        System.out.println(nomJour2);  // Mercredi

        // Grouper plusieurs valeurs
        int mois = 7;
        String saison = switch (mois) {
            case 12, 1, 2 -> "Hiver";
            case 3, 4, 5 -> "Printemps";
            case 6, 7, 8 -> "Été";
            case 9, 10, 11 -> "Automne";
            default -> "Mois invalide";
        };

        System.out.println(saison);  // Été

        // Avec bloc de code
        int score = 85;
        String mention = switch (score / 10) {
            case 10, 9 -> {
                System.out.println("Performance exceptionnelle");
                yield "Excellent";
            }
            case 8 -> "Très bien";
            case 7 -> "Bien";
            case 6 -> "Assez bien";
            case 5 -> "Passable";
            default -> "Insuffisant";
        };

        System.out.println("Mention: " + mention);
    }
}

Note : Les switch expressions sont disponibles à partir de Java 14. Si vous utilisez une version antérieure, utilisez la syntaxe traditionnelle avec break.

Instructions conditionnelles imbriquées

Les conditions imbriquées (nested conditions) permettent de placer une structure conditionnelle à l'intérieur d'une autre. C'est utile pour des logiques complexes nécessitant plusieurs niveaux de décision, mais attention à ne pas abuser de l'imbrication qui rend le code difficile à lire.

public class ConditionsImbriquees {
    public static void main(String[] args) {
        // Exemple 1: Validation d'accès
        int age = 25;
        boolean permis = true;
        boolean assurance = true;

        if (age >= 18) {
            System.out.println("Âge valide");

            if (permis) {
                System.out.println("Permis valide");

                if (assurance) {
                    System.out.println("Accès autorisé - Location possible");
                } else {
                    System.out.println("Assurance requise");
                }
            } else {
                System.out.println("Permis de conduire requis");
            }
        } else {
            System.out.println("Âge minimum: 18 ans");
        }

        // Exemple 2: Calcul de prix avec réductions
        double prixBase = 100.0;
        int quantite = 15;
        boolean estMembre = true;
        double prixFinal = prixBase * quantite;

        if (quantite >= 10) {
            prixFinal *= 0.9;  // 10% de réduction
            System.out.println("Remise quantité appliquée");

            if (estMembre) {
                prixFinal *= 0.95;  // 5% supplémentaire pour les membres
                System.out.println("Remise membre appliquée");
            }
        } else {
            if (estMembre) {
                prixFinal *= 0.98;  // 2% pour les membres
                System.out.println("Remise membre appliquée");
            }
        }

        System.out.println("Prix final: " + prixFinal + "€");

        // Meilleure approche: conditions combinées
        double prix2 = prixBase * quantite;
        boolean remiseQuantite = quantite >= 10;

        if (remiseQuantite && estMembre) {
            prix2 *= 0.855;  // 0.9 * 0.95
            System.out.println("Double remise");
        } else if (remiseQuantite) {
            prix2 *= 0.9;
            System.out.println("Remise quantité");
        } else if (estMembre) {
            prix2 *= 0.98;
            System.out.println("Remise membre");
        }

        System.out.println("Prix: " + prix2 + "€");
    }
}

Bonne pratique : Évitez d'imbriquer plus de 3 niveaux de conditions. Si votre code devient trop complexe, envisagez d'utiliser des méthodes séparées ou de combiner les conditions avec des opérateurs logiques (&&, ||).

Opérateur ternaire : alternative compacte

L'opérateur ternaire ? : est une forme condensée du if-else pour les affectations simples. Il est très utile pour rendre le code plus concis, mais ne doit être utilisé que pour des cas simples afin de préserver la lisibilité.

// Syntaxe: condition ? valeurSiVrai : valeurSiFaux
variable = (condition) ? valeur1 : valeur2;

// Exemple avec if-else
int age = 20;
String statut;
if (age >= 18) {
    statut = "Majeur";
} else {
    statut = "Mineur";
}

// Même exemple avec opérateur ternaire
String statut2 = (age >= 18) ? "Majeur" : "Mineur";

Exemples pratiques d'opérateur ternaire

public class OperateurTernaire {
    public static void main(String[] args) {
        // Trouver le maximum
        int a = 15;
        int b = 20;
        int max = (a > b) ? a : b;
        System.out.println("Maximum: " + max);  // 20

        // Vérifier la parité
        int nombre = 7;
        String parite = (nombre % 2 == 0) ? "pair" : "impair";
        System.out.println(nombre + " est " + parite);

        // Afficher le signe
        int valeur = -5;
        String signe = (valeur >= 0) ? "positif" : "négatif";
        System.out.println("Le nombre est " + signe);

        // Prix avec ou sans remise
        double prix = 100.0;
        boolean client = true;
        double prixFinal = client ? prix * 0.9 : prix;
        System.out.println("Prix: " + prixFinal + "€");

        // Message de bienvenue
        String nom = "Alice";
        System.out.println((nom != null) ? "Bonjour " + nom : "Bonjour invité");

        // Ternaire imbriqué (à éviter si possible)
        int score = 85;
        String mention = (score >= 90) ? "Excellent" :
                        (score >= 70) ? "Bien" :
                        (score >= 50) ? "Passable" : "Insuffisant";
        System.out.println("Mention: " + mention);
    }
}

Validation et gestion d'erreurs

Les structures conditionnelles sont essentielles pour valider les données (validation) et gérer les cas d'erreur. Voici des exemples pratiques de validation couramment utilisés dans les applications Java.

import java.util.Scanner;

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

        // Validation d'âge
        System.out.print("Entrez votre âge: ");
        int age = scanner.nextInt();

        if (age < 0) {
            System.out.println("Erreur: L'âge ne peut pas être négatif");
        } else if (age > 150) {
            System.out.println("Erreur: Âge invalide");
        } else {
            System.out.println("Âge valide: " + age + " ans");
        }

        // Validation de String
        scanner.nextLine();  // Consommer la ligne restante
        System.out.print("Entrez votre nom: ");
        String nom = scanner.nextLine();

        if (nom == null || nom.trim().isEmpty()) {
            System.out.println("Erreur: Le nom est obligatoire");
        } else if (nom.length() < 2) {
            System.out.println("Erreur: Le nom doit contenir au moins 2 caractères");
        } else if (nom.length() > 50) {
            System.out.println("Erreur: Le nom est trop long (max 50 caractères)");
        } else {
            System.out.println("Nom valide: " + nom);
        }

        // Validation d'email (simple)
        System.out.print("Entrez votre email: ");
        String email = scanner.nextLine();

        if (email == null || !email.contains("@") || !email.contains(".")) {
            System.out.println("Erreur: Format d'email invalide");
        } else {
            System.out.println("Email valide: " + email);
        }

        // Validation de mot de passe
        System.out.print("Entrez votre mot de passe: ");
        String password = scanner.nextLine();

        boolean longueurOk = password.length() >= 8;
        boolean contientChiffre = password.matches(".*\\d.*");
        boolean contientMajuscule = password.matches(".*[A-Z].*");

        if (!longueurOk) {
            System.out.println("Erreur: Le mot de passe doit contenir au moins 8 caractères");
        } else if (!contientChiffre) {
            System.out.println("Erreur: Le mot de passe doit contenir au moins un chiffre");
        } else if (!contientMajuscule) {
            System.out.println("Erreur: Le mot de passe doit contenir au moins une majuscule");
        } else {
            System.out.println("Mot de passe valide");
        }

        scanner.close();
    }
}

Exemple complet : système de notation

import java.util.Scanner;

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

        System.out.println("=== Système de Notation ===");
        System.out.print("Entrez la note (0-100): ");
        int note = scanner.nextInt();

        // Validation de la note
        if (note < 0 || note > 100) {
            System.out.println("Erreur: La note doit être entre 0 et 100");
            return;
        }

        // Déterminer la mention
        String mention;
        String appreciation;
        boolean admis;

        if (note >= 90) {
            mention = "Excellent";
            appreciation = "Félicitations ! Performance exceptionnelle.";
            admis = true;
        } else if (note >= 80) {
            mention = "Très bien";
            appreciation = "Excellent travail !";
            admis = true;
        } else if (note >= 70) {
            mention = "Bien";
            appreciation = "Bon travail, continuez ainsi.";
            admis = true;
        } else if (note >= 60) {
            mention = "Assez bien";
            appreciation = "Résultat satisfaisant.";
            admis = true;
        } else if (note >= 50) {
            mention = "Passable";
            appreciation = "Réussite de justesse, des efforts sont nécessaires.";
            admis = true;
        } else {
            mention = "Insuffisant";
            appreciation = "Malheureusement, vous devez repasser l'examen.";
            admis = false;
        }

        // Afficher les résultats
        System.out.println("\n--- Résultats ---");
        System.out.println("Note: " + note + "/100");
        System.out.println("Mention: " + mention);
        System.out.println("Statut: " + (admis ? "ADMIS" : "REFUSÉ"));
        System.out.println(appreciation);

        // Conseils personnalisés
        System.out.println("\n--- Conseils ---");
        if (note >= 90) {
            System.out.println("Maintenez ce niveau d'excellence !");
        } else if (note >= 70) {
            System.out.println("Très bon niveau, continuez à progresser.");
        } else if (note >= 50) {
            System.out.println("Travaillez davantage pour améliorer vos résultats.");
        } else {
            System.out.println("Une révision approfondie est nécessaire.");
        }

        scanner.close();
    }
}

Bonnes pratiques pour les structures conditionnelles

  • Utilisez toujours les accolades même pour une seule instruction
  • Évitez les conditions trop complexes : divisez-les en variables booléennes intermédiaires
  • Préférez switch à if-else-if pour tester une même variable contre plusieurs valeurs
  • Limitez l'imbrication à 2-3 niveaux maximum pour la lisibilité
  • Testez d'abord les cas les plus fréquents pour optimiser les performances
  • Utilisez l'opérateur ternaire uniquement pour des affectations simples
  • Validez les entrées utilisateur avant de les traiter
  • Gérez le cas default dans les switch pour couvrir tous les scénarios
  • Utilisez des méthodes pour extraire la logique complexe
  • N'oubliez pas le break dans les switch (sauf volonté de fall-through)

Erreurs courantes à éviter

1. Oublier les accolades

// MAUVAIS - peut causer des bugs
if (age >= 18)
    System.out.println("Majeur");
    System.out.println("Accès autorisé");  // Toujours exécuté !

// BON
if (age >= 18) {
    System.out.println("Majeur");
    System.out.println("Accès autorisé");
}

2. Utiliser == pour comparer des String

String nom = "Java";

// MAUVAIS - compare les références
if (nom == "Java") {
    System.out.println("Java détecté");
}

// BON - compare le contenu
if (nom.equals("Java")) {
    System.out.println("Java détecté");
}

3. Oublier le break dans un switch

int jour = 1;

// MAUVAIS - fall-through non voulu
switch (jour) {
    case 1:
        System.out.println("Lundi");
    case 2:
        System.out.println("Mardi");  // Sera aussi affiché !
        break;
}

// BON
switch (jour) {
    case 1:
        System.out.println("Lundi");
        break;
    case 2:
        System.out.println("Mardi");
        break;
}

4. NullPointerException avec les conditions

String nom = null;

// MAUVAIS - NullPointerException
if (nom.equals("Java")) {
    System.out.println("Java");
}

// BON - vérifier null d'abord
if (nom != null && nom.equals("Java")) {
    System.out.println("Java");
}

// MEILLEUR - ordre inversé (si comparaison avec constante)
if ("Java".equals(nom)) {
    System.out.println("Java");
}

Questions fréquentes

Quand utiliser if-else vs switch ?

Utilisez switch quand vous comparez une même variable à plusieurs valeurs constantes. Utilisez if-else pour des conditions plus complexes ou des intervalles de valeurs.

Peut-on utiliser des variables dans les case ?

Non, les valeurs des case doivent être des constantes connues à la compilation. Vous pouvez utiliser des variables final ou des littéraux.

L'opérateur ternaire est-il plus rapide que if-else ?

Non, les performances sont identiques. L'opérateur ternaire est simplement une syntaxe plus compacte pour les affectations conditionnelles simples.

Ressources pour approfondir

Conclusion

Les structures de contrôle sont essentielles pour créer des programmes dynamiques et intelligents. Maîtriser les instructions if, else, else-if et switch vous permet de prendre des décisions dans votre code, de valider des données et de créer une logique métier sophistiquée.

Commencez par les structures simples (if-else), puis progressez vers des conditions plus complexes et des switch. N'oubliez pas les bonnes pratiques : toujours utiliser des accolades, éviter l'imbrication excessive et valider les entrées utilisateur.

Pour continuer votre apprentissage, découvrez les boucles Java qui permettent de répéter des blocs de code de manière efficace.