{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "title: Exceptions en Java\n",
    "description: Ce cours couvre la gestion et la création des exceptions en Java, en se concentrant sur la sécurisation des programmes en anticipant, détectant et réagissant aux erreurs.\n",
    "categories:\n",
    "  - Java\n",
    "  - I111\n",
    "  - PO43\n",
    "  - Lecture\n",
    "provide_notes: true\n",
    "provide_slides: true\n",
    "jupyter: java\n",
    "\n",
    "echo: true\n",
    "output: true\n",
    "\n",
    "---\n",
    "\n",
    "\n",
    "\n",
    "## Objectifs d'apprentissage\n",
    "\n",
    "- Comprendre le concept des exceptions en Java\n",
    "- Apprendre à gérer les exceptions efficacement\n",
    "- Créer des exceptions personnalisées\n",
    "- Mettre en oeuvre les meilleures pratiques pour la gestion des exceptions\n",
    "\n",
    "## Introduction aux Exceptions\n",
    "\n",
    "- **Qu'est-ce qu'une exception ?**\n",
    "  - Une exception est un événement qui interrompt le flux normal d'un programme.\n",
    "- **Pourquoi les exceptions sont-elles importantes ?**\n",
    "  - Elles permettent de gérer les erreurs de manière structurée et de maintenir le flux normal du programme.\n",
    "\n",
    "### Objectifs de la Gestion des Exceptions\n",
    "- **Anticiper les erreurs** : Identifier les scénarios d'erreur potentiels.\n",
    "- **Détecter les erreurs** : Implémenter des mécanismes pour capturer les erreurs lorsqu'elles se produisent.\n",
    "- **Réagir aux erreurs** : Définir comment le programme doit répondre à différents types d'erreurs.\n",
    "\n",
    "## Pourquoi sécuriser un programme ?\n",
    "\n",
    "- **Anticiper les erreurs** : Identifier les scénarios d'erreur potentiels.\n",
    "- **Détecter les erreurs** : Implémenter des mécanismes pour capturer les erreurs lorsqu'elles se produisent.\n",
    "- **Réagir aux erreurs** : Définir comment le programme doit répondre à différents types d'erreurs.\n",
    "\n",
    "## Sécuriser un programme **sans gestion spécifique des erreurs**\n",
    "\n",
    "- **Prédiction des erreurs** : Analyser le code et l'utilisation pour identifier les erreurs possibles.\n",
    "- **Ajout de code de prévention/détection** : Utiliser des vérifications de conditions (`if` statements) et des assertions pour détecter les erreurs.\n",
    "- **Réactions aux erreurs** : Définir comment gérer les erreurs :\n",
    "  - **Avertissements** : Informer l'utilisateur ou le développeur.\n",
    "  - **Corrections dynamiques** : Tenter de corriger l'erreur automatiquement.\n",
    "  - **Arrêts contrôlés** : Arrêter le programme de manière sécurisée.\n",
    "- **Propagation des erreurs** : Décider si l'appelant ou l'appelé gère l'erreur.\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Entrée invalide : l'entrée ne doit pas être nulle ou vide.\n"
     ]
    }
   ],
   "source": [
    "public boolean validateInput(String input) {\n",
    "    if (input == null || input.isEmpty()) {\n",
    "        System.err.println(\"Entrée invalide : l'entrée ne doit pas être nulle ou vide.\");\n",
    "        return false;\n",
    "    }\n",
    "    return true;\n",
    "}\n",
    "\n",
    "public void processInput(String input) {\n",
    "    if (validateInput(input)) {\n",
    "        // Traitement de l'entrée\n",
    "        System.out.println(\"Traitement de l'entrée : \" + input);\n",
    "    }\n",
    "}\n",
    "\n",
    "processInput(null);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Défis\n",
    "\n",
    "- **Lisibilité** : Mélanger le code de test avec le code de l'application rend la lecture difficile.\n",
    "- **Maintenabilité** : Difficile de maintenir le code de gestion des erreurs.\n",
    "- **Responsabilité** : Incertitude sur qui doit gérer l'erreur, l'appelant ou l'appelé.\n",
    "\n",
    "## Approche de Java pour la sécurité\n",
    "\n",
    "- Java propose un mécanisme robuste pour gérer les erreurs via les exceptions.\n",
    "- **Avantages** :\n",
    "  - Sépare le code de gestion des erreurs du code régulier.\n",
    "  - Propage les erreurs dans la pile d'appels.\n",
    "  - Regroupe et différencie les types d'erreurs.\n",
    "\n",
    "### La classe `Exception`\n",
    "\n",
    "- **Définition** : La classe `Exception` est la classe de base pour toutes les exceptions en Java.\n",
    "  - Les exceptions sont des objets qui encapsulent des informations sur les erreurs.\n",
    "\n",
    "- **Constructeurs** :\n",
    "  - `Exception(String message)`: Construit une nouvelle exception avec le message détaillé spécifié.\n",
    "  - `Exception(String message, Throwable cause)`: Construit une nouvelle exception avec le message détaillé spécifié et la cause.\n",
    "    - La \"cause\" est éventuellement une autre exception qui a conduit à l'exception actuelle. \n",
    "    - Cela permet de chaîner les exceptions pour mieux comprendre la séquence d'erreurs qui a conduit à un problème.\n",
    "\n",
    "- Exceptions prédéfinies : `IllegalArgumentException`, `NullPointerException`, `ArrayIndexOutOfBoundsException`, etc.\n",
    "\n",
    "- **Méthodes** :\n",
    "    - `String getMessage()`: Retourne le message détaillé de l'exception.\n",
    "    - `Throwable getCause()`: Retourne la cause de l'exception.\n",
    "\n",
    "- printstacktrace() : Affiche la trace de la pile\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Le message d'erreur est : Message d'erreur\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "java.lang.Exception: Message d'erreur\n",
      "\tat REPL.$JShell$62C.do_it$($JShell$62C.java:52)\n",
      "\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)\n",
      "\tat java.base/java.lang.reflect.Method.invoke(Method.java:580)\n",
      "\tat io.github.spencerpark.ijava.execution.IJavaExecutionControl.lambda$execute$1(IJavaExecutionControl.java:95)\n",
      "\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)\n",
      "\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\n",
      "\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\n",
      "\tat java.base/java.lang.Thread.run(Thread.java:1583)\n"
     ]
    }
   ],
   "source": [
    "//|error: true \n",
    "Exception e = new Exception(\"Message d'erreur\");\n",
    "System.out.println(\"Le message d'erreur est : %s\".formatted(e.getMessage()));\n",
    "e.printStackTrace(); // Affiche la trace de la pile"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Types d'Exceptions\n",
    "\n",
    "- **Exceptions vérifiées (Checked Exceptions)** :\n",
    "  - Vérifiées à la compilation.\n",
    "  - Héritent de `Exception` (mais pas de `RuntimeException`) qui hérite de `Throwable`.\n",
    "  - Doivent être gérées ou déclarées dans la signature de la méthode avec `throws`.\n",
    "  - Exemple : `IOException`, `SQLException`\n",
    "\n",
    "- **Exceptions non vérifiées (Unchecked Exceptions)** :\n",
    "  - Vérifiées à l'exécution.\n",
    "  - Héritent de `RuntimeException` (qui hérite de `Exception`).\n",
    "  - Exemple : `NullPointerException`, `ArrayIndexOutOfBoundsException`\n",
    "\n",
    "- **Erreurs (Errors)** :\n",
    "  - Problèmes sérieux qu'une application ne devrait pas essayer de capturer.\n",
    "  - Héritent de `Error` qui hérite de `Throwable`.\n",
    "  - Exemple : `OutOfMemoryError`, `StackOverflowError`\n",
    "\n",
    "---\n",
    "\n",
    "```java\n",
    "// Hiérarchie des exceptions\n",
    "Throwable\n",
    "    ├── Exception\n",
    "    │   ├── IOException\n",
    "    │   ├── SQLException\n",
    "    │   └── RuntimeException\n",
    "    │       └── NullPointerException\n",
    "    └── Error\n",
    "            ├── OutOfMemoryError\n",
    "            └── StackOverflowError\n",
    "```\n",
    "\n",
    "## Syntaxe de base de la Gestion des Exceptions\n",
    "\n",
    "- **Bloc `try-catch`** : Utilisé pour entourer le code qui peut générer une exception.\n",
    "- **Bloc `try-finally`** : Utilisé pour exécuter un code qui doit s'exécuter, qu'une exception soit levée ou non.\n",
    "- **Bloc `try-catch-finally`** : Combinaison des deux blocs précédents.\n",
    "\n",
    "```java\n",
    "try {\n",
    "    // Code pouvant générer une exception\n",
    "} catch (ExceptionType1 e1) {\n",
    "    // Gérer l'exception de type ExceptionType1\n",
    "} catch (ExceptionType2 e2) {\n",
    "    // Gérer l'exception de type ExceptionType2\n",
    "} finally {\n",
    "    // Code qui s'exécute toujours\n",
    "}\n",
    "```\n",
    "\n",
    "### Exemple avec l'ouverture d'un fichier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//|output: false\n",
    "import java.util.logging.Logger;\n",
    "\n",
    "Logger logger = Logger.getLogger(\"Notebook\");\n",
    "\n",
    "import java.io.*;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ubuntu 24.04.1 LTS\n"
     ]
    }
   ],
   "source": [
    "try (BufferedReader reader = new BufferedReader(new FileReader(\"/etc/issue.net\"))) {\n",
    "    String line;\n",
    "    while ((line = reader.readLine()) != null) {\n",
    "        System.out.println(line);\n",
    "    }\n",
    "} catch (FileNotFoundException e) {\n",
    "    logger.severe(\"Erreur de fichier non trouvé %s\".formatted(e.getMessage()));\n",
    "} catch (IOException e) {\n",
    "    logger.severe(\"Erreur de lecture du fichier %s\".formatted(e.getMessage()));\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Création d'Exceptions Personnalisées\n",
    "\n",
    "- Les exceptions personnalisées permettent de définir des erreurs spécifiques à une application.\n",
    "- Elles héritent de la classe `Exception` ou d'une de ses sous-classes.\n",
    "\n",
    "- **Définir une nouvelle classe d'exception** :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {
    "md-indent": "  ",
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public class CustomException extends Exception {\n",
    "    public CustomException(String message) {\n",
    "        super(message);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- `throws` : indique que la méthode peut lancer une exception qui doit être gérée par l'appelant.\n",
    "\n",
    "- **Lancer une exception personnalisée** :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {
    "md-indent": "  ",
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "ename": "EvalException",
     "evalue": "Message d'erreur personnalisé",
     "output_type": "error",
     "traceback": [
      "Execution exception",
      "---------------------------------------------------------------------------",
      "",
      "REPL.$JShell$78E$CustomException: Message d'erreur personnalisé",
      "\tat .someMethod(#79:1)",
      "\tat .(#107:1)"
     ]
    }
   ],
   "source": [
    "//|error: true\n",
    "boolean someCondition = true;\n",
    "\n",
    "public void someMethod() throws CustomException {\n",
    "    if (someCondition) {\n",
    "        throw new CustomException(\"Message d'erreur personnalisé\");\n",
    "    }\n",
    "}\n",
    "\n",
    "someMethod();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Autoclôture des Ressources\n",
    "\n",
    "- Java 7 a introduit le concept d'autoclôture des ressources pour simplifier la gestion des ressources.\n",
    "- Les ressources qui implantent l'interface `AutoCloseable` peuvent être utilisées dans un bloc `try-with-resources`.\n",
    "- Les ressources sont automatiquement fermées à la fin du bloc `try`.\n",
    "- Pas besoin de bloc `finally` pour fermer les ressources.\n",
    "\n",
    "### Exemple avec l'ouverture d'un fichier"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ubuntu 24.04.1 LTS\n"
     ]
    }
   ],
   "source": [
    "public class MyDataException extends Exception {\n",
    "    public MyDataException(String message, Throwable cause) {\n",
    "        super(message, cause);\n",
    "    }\n",
    "}\n",
    "\n",
    "public void readIssueFile(String filepath) throws MyDataException {\n",
    "    try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {\n",
    "        String line;\n",
    "        while ((line = reader.readLine()) != null) {\n",
    "            System.out.println(line);\n",
    "        }\n",
    "    } catch (FileNotFoundException e) {\n",
    "        throw new MyDataException(\"Erreur de fichier non trouvé\", e);\n",
    "    } catch (IOException e) {\n",
    "        throw new MyDataException(\"Erreur de lecture du fichier\", e);\n",
    "    }\n",
    "}\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Ubuntu 24.04.1 LTS\n"
     ]
    }
   ],
   "source": [
    "readIssueFile(\"/etc/issue.net\");"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "ename": "EvalException",
     "evalue": "Erreur de fichier non trouvé",
     "output_type": "error",
     "traceback": [
      "Execution exception",
      "---------------------------------------------------------------------------",
      "",
      "REPL.$JShell$85$MyDataException: Erreur de fichier non trouvé",
      "\tat .readIssueFile(#89:1)",
      "\tat .(#93:2)"
     ]
    }
   ],
   "source": [
    "//|error: true\n",
    "readIssueFile(\"/etc/missingfile\");"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Propagation des Exceptions\n",
    "\n",
    "- **Définition** : La propagation des exceptions est le processus par lequel une exception est transmise dans la pile d'appels jusqu'à ce qu'elle soit capturée par un bloc `catch` approprié ou jusqu'à ce que le programme se termine.\n",
    "\n",
    "- **Envelopper une exception** : Une méthode peut envelopper une exception dans une autre exception plus spécifique avant de la propager. Cela permet de fournir plus de contexte sur l'erreur.\n",
    "\n",
    "- **Traitement total ou partiel** : Un bloc `catch` peut traiter une exception partiellement et ensuite la propager ou en propager une autre. Cela permet de gérer certaines parties de l'erreur tout en laissant d'autres parties être gérées par des niveaux supérieurs.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemple d'Enveloppement d'Exception"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Exception capturée : Erreur enveloppée dans method1\n",
      "REPL.$JShell$78C$CustomException: Erreur enveloppée dans method1\n",
      "\tat REPL.$JShell$97C.method1($JShell$97C.java:58)\n",
      "\tat REPL.$JShell$94B.test($JShell$94B.java:56)\n",
      "\tat REPL.$JShell$99.do_it$($JShell$99.java:54)\n",
      "\tat java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)\n",
      "\tat java.base/java.lang.reflect.Method.invoke(Method.java:580)\n",
      "\tat io.github.spencerpark.ijava.execution.IJavaExecutionControl.lambda$execute$1(IJavaExecutionControl.java:95)\n",
      "\tat java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317)\n",
      "\tat java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144)\n",
      "\tat java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642)\n",
      "\tat java.base/java.lang.Thread.run(Thread.java:1583)\n",
      "Caused by: REPL.$JShell$95D$CauseException: Erreur dans method2\n",
      "\tat REPL.$JShell$96C.method2($JShell$96C.java:55)\n",
      "\tat REPL.$JShell$97C.method1($JShell$97C.java:56)\n",
      "\t... 9 more\n"
     ]
    }
   ],
   "source": [
    "//|error: true\n",
    "\n",
    "    public class CauseException extends Exception {\n",
    "        public CauseException(String message) {\n",
    "            super(message);\n",
    "        }\n",
    "    }\n",
    "    \n",
    "    public void method2() throws CauseException {\n",
    "        throw new CauseException(\"Erreur dans method2\");\n",
    "    }\n",
    "    \n",
    "    public class CustomException extends Exception {\n",
    "        public CustomException(String message, Throwable cause) {\n",
    "            super(message, cause);\n",
    "        }\n",
    "    }\n",
    "\n",
    "    public void method1() throws CustomException {\n",
    "        try {\n",
    "            method2();\n",
    "        } catch (CauseException e) {\n",
    "            throw new CustomException(\"Erreur enveloppée dans method1\", e);\n",
    "        }\n",
    "    }\n",
    "\n",
    "    public void test() {\n",
    "        try {\n",
    "            method1();\n",
    "        } catch (CustomException e) {\n",
    "            System.err.println(\"Exception capturée : \" + e.getMessage());\n",
    "            e.printStackTrace();\n",
    "        }\n",
    "    }\n",
    "\n",
    "    test();"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Avantages de la Propagation des Exceptions\n",
    "\n",
    "- **Séparation des préoccupations** : Permet de séparer le code de gestion des erreurs du code de logique métier.\n",
    "- **Réutilisabilité** : Facilite la réutilisation des méthodes sans avoir à dupliquer le code de gestion des erreurs.\n",
    "- **Lisibilité** : Améliore la lisibilité du code en réduisant le nombre de blocs `try-catch` imbriqués.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Assertions\n",
    "\n",
    "- Les assertions sont des outils de vérification utilisés pour tester les hypothèses faites par le programmeur.\n",
    "- Elles permettent de détecter les erreurs de logique dans le code pendant le développement et les tests.\n",
    "- Utilisation de l'instruction `assert` :\n",
    "\n",
    "  ```java\n",
    "  assert condition : message;\n",
    "  ```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Exemple d'utilisation\n",
    "\n",
    "- Vérification d'une condition simple :\n",
    "\n",
    "  ```java\n",
    "  int age = -1;\n",
    "  assert age >= 0 : \"L'âge ne peut pas être négatif : \" + age;\n",
    "  System.out.println(\"L'âge est : \" + age);\n",
    "  ```\n",
    "\n",
    "- Par défaut, les assertions sont désactivées à l'exécution.\n",
    "- Pour les activer, utilisez l'option `-ea` (ou `-enableassertions`) lors de l'exécution du programme :\n",
    "\n",
    "  ```sh\n",
    "  java -ea AssertionExample\n",
    "  ```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### Meilleures Pratiques\n",
    "\n",
    "- **Utiliser des exceptions spécifiques** : Capturer des exceptions spécifiques plutôt qu'une exception générique.\n",
    "- **Éviter de masquer les exceptions** : Ne pas capturer une exception sans la gérer.\n",
    "- **Journaliser les exceptions** : Toujours journaliser les exceptions pour le débogage.\n",
    "- **Nettoyer les ressources** : Utiliser le bloc `finally` ou try-with-resources pour nettoyer les ressources.\n",
    "- **Documenter les exceptions** : Utiliser Javadoc pour documenter les exceptions qu'une méthode peut lancer.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Exemple 1 : Gestion des Entrées/Sorties de Fichiers"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//|echo: false\n",
    "import java.io.*;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public class FileHandler {\n",
    "    public void readFile(String filePath) {\n",
    "        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {\n",
    "            String line;\n",
    "            while ((line = reader.readLine()) != null) {\n",
    "                System.out.println(line);\n",
    "            }\n",
    "        } catch (FileNotFoundException e) {\n",
    "            System.err.println(\"Fichier non trouvé : \" + e.getMessage());\n",
    "        } catch (IOException e) {\n",
    "            System.err.println(\"Erreur de lecture du fichier : \" + e.getMessage());\n",
    "        }\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemple 2 : Exception Personnalisée"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "public class AgeValidator {\n",
    "    public void validateAge(int age) throws InvalidAgeException {\n",
    "        if (age < 0 || age > 150) {\n",
    "            throw new InvalidAgeException(\"Âge invalide : \" + age);\n",
    "        }\n",
    "    }\n",
    "}\n",
    "\n",
    "public class InvalidAgeException extends Exception {\n",
    "    public InvalidAgeException(String message) {\n",
    "        super(message);\n",
    "    }\n",
    "}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exemple 3 : Utilisation de try-with-resources"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "//|output: false\n",
    "import java.sql.*;"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "java"
    }
   },
   "outputs": [],
   "source": [
    "    public void connectToDatabase() {\n",
    "        String url = \"jdbc:mysql://localhost:3306/mydatabase\";\n",
    "        String user = \"root\";\n",
    "        String password = \"password\";\n",
    "\n",
    "        try (Connection conn = DriverManager.getConnection(url, user, password);\n",
    "             Statement stmt = conn.createStatement()) {\n",
    "            ResultSet rs = stmt.executeQuery(\"SELECT * FROM mytable\");\n",
    "            while (rs.next()) {\n",
    "                System.out.println(rs.getString(\"column1\"));\n",
    "            }\n",
    "        } catch (SQLException e) {\n",
    "            System.err.println(\"Erreur de base de données : \" + e.getMessage());\n",
    "        }\n",
    "    }"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "- La gestion des exceptions est cruciale pour construire des applications robustes et sécurisées.\n",
    "- Java fournit un mécanisme complet pour gérer les exceptions.\n",
    "- Suivre les meilleures pratiques assure un code maintenable et lisible.\n",
    "- Références\n",
    "  - [Documentation Java sur les Exceptions](https://docs.oracle.com/javase/tutorial/essential/exceptions/)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "java",
   "language": "java",
   "name": "java",
   "path": "/opt/conda/share/jupyter/kernels/java"
  },
  "language_info": {
   "codemirror_mode": "java",
   "file_extension": ".jshell",
   "mimetype": "text/x-java-source",
   "name": "Java",
   "pygments_lexer": "java",
   "version": "21.0.5+11-LTS"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
