Java · Fiche 08

Exceptions

Gestion des erreurs en Java : hiérarchie des exceptions, checked vs unchecked, try-catch-finally, try-with-resources et exceptions personnalisées.

Gestion des erreurs et exceptions en Java.

🌳 Hiérarchie des exceptions

Throwable
├── Error (Erreurs système, non récupérables)
│   ├── OutOfMemoryError
│   ├── StackOverflowError
│   └── VirtualMachineError
└── Exception
    ├── RuntimeException (Unchecked Exceptions)
    │   ├── NullPointerException
    │   ├── IllegalArgumentException
    │   ├── IndexOutOfBoundsException
    │   └── ClassCastException
    └── Checked Exceptions (doivent être gérées)
        ├── IOException
        ├── SQLException
        ├── ClassNotFoundException
        └── ParseException

🎯 Types d’exceptions

Checked Exceptions

Elles doivent être gérées ou déclarées.

// Doit être dans try-catch ou throws
public void readFile(String filename) throws IOException {
    FileReader file = new FileReader(filename); // IOException possible
    // ...
}

// Ou gestion avec try-catch
public void safeReadFile(String filename) {
    try {
        FileReader file = new FileReader(filename);
        // ...
    } catch (IOException e) {
        System.err.println("Erreur lecture: " + e.getMessage());
    }
}

Unchecked Exceptions

Optionnelles à gérer (RuntimeException).

// Pas obligé de gérer, mais recommandé
public void divide(int a, int b) {
    if (b == 0) {
        throw new IllegalArgumentException("Division par zéro");
    }
    int result = a / b; // ArithmeticException possible
}

// Gestion optionnelle
public void safeDivide(int a, int b) {
    try {
        int result = a / b;
        System.out.println("Résultat: " + result);
    } catch (ArithmeticException e) {
        System.err.println("Erreur: " + e.getMessage());
    }
}

🛡️ Try-Catch-Finally

Structure complète

public void complexOperation() {
    FileInputStream fis = null;
    try {
        fis = new FileInputStream("data.txt");
        // Opérations risquées
        int data = fis.read();

    } catch (FileNotFoundException e) {
        System.err.println("Fichier non trouvé: " + e.getMessage());

    } catch (IOException e) {
        System.err.println("Erreur I/O: " + e.getMessage());

    } catch (Exception e) {
        // Catch générique (à éviter généralement)
        System.err.println("Erreur inattendue: " + e.getMessage());

    } finally {
        // TOUJOURS exécuté
        if (fis != null) {
            try {
                fis.close();
            } catch (IOException e) {
                System.err.println("Erreur fermeture: " + e.getMessage());
            }
        }
        System.out.println("Nettoyage terminé");
    }
}

Point clé : les blocs catch s’évaluent dans l’ordre : toujours placer les exceptions les plus spécifiques avant les plus générales, sinon le code ne compile pas (« exception already caught »).

Multi-catch (Java 7+)

public void multiCatchExample() {
    try {
        // Opérations diverses
        String str = null;
        int length = str.length(); // NullPointerException

        int[] array = new int[5];
        int value = array[10];     // ArrayIndexOutOfBoundsException

    } catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
        // Gestion commune pour plusieurs exceptions
        System.err.println("Erreur de programmation: " + e.getMessage());

    } catch (RuntimeException e) {
        // Autres RuntimeExceptions
        System.err.println("Autre erreur runtime: " + e.getMessage());
    }
}

// Récupération de l'exception originale
public void rethrowExample() throws Exception {
    try {
        riskyOperation();
    } catch (Exception e) {
        // Log et relance
        System.err.println("Erreur capturée: " + e.getMessage());
        throw e; // Relance la même exception
    }
}

🔄 Try-with-Resources (Java 7+)

Gestion automatique des ressources

// Avant Java 7 (verbeux)
public void oldWay() {
    FileInputStream fis = null;
    BufferedReader br = null;
    try {
        fis = new FileInputStream("file.txt");
        br = new BufferedReader(new InputStreamReader(fis));
        String line = br.readLine();
        // ...
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
        if (br != null) {
            try { br.close(); } catch (IOException e) { }
        }
        if (fis != null) {
            try { fis.close(); } catch (IOException e) { }
        }
    }
}

// Java 7+ (automatique)
public void newWay() {
    try (FileInputStream fis = new FileInputStream("file.txt");
         BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {

        String line = br.readLine();
        // ...

    } catch (IOException e) {
        e.printStackTrace();
    }
    // Fermeture automatique de br et fis !
}

Ressources personnalisées

// Implémenter AutoCloseable
public class DatabaseConnection implements AutoCloseable {
    private Connection connection;

    public DatabaseConnection(String url) throws SQLException {
        this.connection = DriverManager.getConnection(url);
        System.out.println("Connexion ouverte");
    }

    public void executeQuery(String sql) throws SQLException {
        // Exécution de la requête
    }

    @Override
    public void close() throws SQLException {
        if (connection != null && !connection.isClosed()) {
            connection.close();
            System.out.println("Connexion fermée");
        }
    }
}

// Utilisation
public void useDatabase() {
    try (DatabaseConnection db = new DatabaseConnection("jdbc:...")) {
        db.executeQuery("SELECT * FROM users");
        // ...
    } catch (SQLException e) {
        e.printStackTrace();
    }
    // close() appelé automatiquement
}

🎨 Exceptions personnalisées

Checked Exception personnalisée

public class InsufficientFundsException extends Exception {
    private double amount;
    private double balance;

    public InsufficientFundsException(double amount, double balance) {
        super("Fonds insuffisants: tentative de retrait de " + amount +
              " avec un solde de " + balance);
        this.amount = amount;
        this.balance = balance;
    }

    public double getAmount() { return amount; }
    public double getBalance() { return balance; }
    public double getShortfall() { return amount - balance; }
}

public class BankAccount {
    private double balance;

    public void withdraw(double amount) throws InsufficientFundsException {
        if (amount > balance) {
            throw new InsufficientFundsException(amount, balance);
        }
        balance -= amount;
    }
}

Unchecked Exception personnalisée

public class InvalidEmailException extends RuntimeException {
    private String email;

    public InvalidEmailException(String email) {
        super("Email invalide: " + email);
        this.email = email;
    }

    public InvalidEmailException(String email, Throwable cause) {
        super("Email invalide: " + email, cause);
        this.email = email;
    }

    public String getEmail() { return email; }
}

public class UserService {
    public void createUser(String email) {
        if (!isValidEmail(email)) {
            throw new InvalidEmailException(email);
        }
        // Création de l'utilisateur
    }

    private boolean isValidEmail(String email) {
        return email != null && email.contains("@");
    }
}

✅ Bonnes pratiques

À faire

Être spécifique dans les catch :

try {
    // ...
} catch (FileNotFoundException e) {
    // Gestion spécifique
} catch (IOException e) {
    // Gestion plus générale
}

Utiliser try-with-resources :

try (Resource r = new Resource()) {
    // Utilisation
} // Fermeture automatique

À éviter

Catch vide ou trop générique :

try {
    // ...
} catch (Exception e) {
    // Ne rien faire - MAUVAIS !
}

Utiliser les exceptions pour le contrôle de flux :

// MAUVAIS : exception pour logique normale
try {
    return array[index];
} catch (ArrayIndexOutOfBoundsException e) {
    return null;
}

Interro écrite

8 questions pour valider la fiche. Une seule réponse par question.

Question 1/8Quelle est la différence entre une checked et une unchecked exception ?