Bonjour! Dans la leçon d'aujourd'hui, nous parlerons des exceptions Java. La vie quotidienne est pleine de situations que nous n'anticipons pas. Par exemple, vous vous levez pour le travail le matin et cherchez votre chargeur de téléphone, mais vous ne le trouvez nulle part. Vous allez à la salle de bain pour vous doucher et vous découvrez que les tuyaux sont gelés. Vous montez dans votre voiture, mais elle ne démarre pas. Un être humain est capable de faire face à de telles circonstances imprévues assez facilement. Dans cet article, nous allons essayer de comprendre comment les programmes Java les traitent.
Qu'est-ce qu'une exception Java ?
Dans le monde de la programmation, les erreurs et les situations imprévues dans l'exécution d'un programme sont appelées exceptions. Dans un programme, des exceptions peuvent se produire en raison d'actions utilisateur non valides, d'un espace disque insuffisant ou de la perte de la connexion réseau avec le serveur. Les exceptions peuvent également résulter d'erreurs de programmation ou de l'utilisation incorrecte d'une API. Contrairement aux humains dans le monde réel, un programme doit savoir exactement comment gérer ces situations. Pour cela, Java dispose d'un mécanisme connu sous le nom de gestion des exceptions.Quelques mots sur les mots clés
La gestion des exceptions en Java est basée sur l'utilisation des mots clés suivants dans le programme :- try - définit un bloc de code où une exception peut se produire ;
- catch - définit un bloc de code où les exceptions sont gérées ;
- finally - définit un bloc de code facultatif qui, s'il est présent, est exécuté quels que soient les résultats du bloc try.
- throw - utilisé pour déclencher une exception ;
- throws - utilisé dans la signature de la méthode pour avertir que la méthode peut lever une exception.
// This method reads a string from the keyboard
public String input() throws MyException { // Use throws to warn
// that the method may throw a MyException
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String s = null;
// We use a try block to wrap code that might create an exception. In this case,
// the compiler tells us that the readLine() method in the
// BufferedReader class might throw an I/O exception
try {
s = reader.readLine();
// We use a catch block to wrap the code that handles an IOException
} catch (IOException e) {
System.out.println(e.getMessage());
// We close the read stream in the finally block
} finally {
// An exception might occur when we close the stream if, for example, the stream was not open, so we wrap the code in a try block
try {
reader.close();
// Handle exceptions when closing the read stream
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
if (s.equals("")) {
// We've decided that an empty string will prevent our program from working properly. For example, we use the result of this method to call the substring(1, 2) method. Accordingly, we have to interrupt the program by using throw to generate our own MyException exception type.
throw new MyException("The string cannot be empty!");
}
return s;
}
Pourquoi avons-nous besoin d'exceptions ?
Regardons un exemple du monde réel. Imaginez qu'une section d'autoroute comporte un petit pont avec une capacité de charge limitée. Si une voiture plus lourde que la limite du pont passe dessus, elle pourrait s'effondrer. La situation du conducteur deviendrait, c'est un euphémisme, exceptionnelle. Pour éviter cela, le service des transports installe des panneaux d'avertissement sur la route avant que quelque chose ne se passe mal. Voyant le panneau d'avertissement, un conducteur compare le poids de son véhicule avec le poids maximum pour le pont. Si le véhicule est trop lourd, le conducteur emprunte un itinéraire de contournement. Le service des transports, d'une part, a permis aux camionneurs de modifier leur itinéraire si nécessaire, d'autre part, a averti les conducteurs des dangers sur la route principale et, troisièmement, a averti les conducteurs que le pont ne devait pas être utilisé sous certaines conditions. La possibilité de prévenir et de résoudre des situations exceptionnelles dans un programme, lui permettant de continuer à s'exécuter, est l'une des raisons d'utiliser les exceptions en Java. Le mécanisme d'exception vous permet également de protéger votre code (API) d'une utilisation inappropriée en validant (vérifiant) toutes les entrées. Imaginez maintenant que vous êtes le département des transports pendant une seconde. Tout d'abord, vous devez connaître les endroits où les automobilistes peuvent s'attendre à des problèmes. Deuxièmement, vous devez créer et installer des panneaux d'avertissement. Et enfin, vous devez prévoir des détours si des problèmes surviennent sur l'itinéraire principal. En Java, le mécanisme d'exception fonctionne de manière similaire. Pendant le développement, nous utilisons un bloc try pour créer des "barrières d'exception" autour des sections de code dangereuses, nous fournissons des "routes de secours" à l'aide d'un catch {}bloc, et nous écrivons du code qui devrait s'exécuter quoi qu'il arrive dans un bloc finally{} . Si nous ne pouvons pas fournir de "route de secours" ou si nous voulons laisser le choix à l'utilisateur, nous devons au moins l'avertir du danger. Pourquoi? Imaginez l'indignation d'un automobiliste qui, sans voir un seul panneau d'avertissement, arrive sur un petit pont qu'il ne peut pas traverser ! En programmation, lors de l'écriture de nos classes et méthodes, nous ne pouvons pas toujours prévoir comment elles pourraient être utilisées par d'autres développeurs. En conséquence, nous ne pouvons pas prévoir la manière correcte à 100% de résoudre une situation exceptionnelle. Cela dit, il est de bon ton d'avertir les autres de la possibilité de situations exceptionnelles. Le mécanisme d'exception de Java nous permet de le faire avec les lancersmot clé - essentiellement une déclaration indiquant que le comportement général de notre méthode inclut la levée d'une exception. Ainsi, toute personne utilisant la méthode sait qu'elle doit écrire du code pour gérer les exceptions.Avertir les autres des "problèmes"
Si vous ne prévoyez pas de gérer les exceptions dans votre méthode, mais que vous souhaitez avertir les autres que des exceptions peuvent se produire, utilisez le mot-clé throws . Ce mot-clé dans la signature de la méthode signifie que, sous certaines conditions, la méthode peut lever une exception. Cet avertissement fait partie de l'interface de la méthode et permet à ses utilisateurs d'implémenter leur propre logique de gestion des exceptions. Après les levées, nous spécifions les types d'exceptions levées. Celles-ci descendent généralement de la classe Exception de Java . Puisque Java est un langage orienté objet, toutes les exceptions sont des objets en Java.Hiérarchie des exceptions
Lorsqu'une erreur se produit pendant l'exécution d'un programme, la JVM crée un objet du type approprié à partir de la hiérarchie des exceptions Java - un ensemble d'exceptions possibles qui descendent d'un ancêtre commun - la classe Throwable . Nous pouvons diviser les situations d'exécution exceptionnelles en deux groupes :- Situations à partir desquelles le programme ne peut pas récupérer et poursuivre son fonctionnement normal.
- Situations où la récupération est possible.
Créer une exception
Lorsqu'un programme s'exécute, des exceptions sont générées soit par la JVM, soit manuellement à l'aide d'une instruction throw . Lorsque cela se produit, un objet d'exception est créé en mémoire, le flux principal du programme est interrompu et le gestionnaire d'exceptions de la JVM tente de gérer l'exception.Gestion des exceptions
En Java, nous créons des blocs de code où nous anticipons le besoin de gestion des exceptions à l'aide des constructions try{}catch , try{}catch{}finally et try{}finally{} . Lorsqu'une exception est levée dans un bloc try , la JVM recherche un gestionnaire d'exception approprié dans le bloc catch suivant . Si un bloc catch a le gestionnaire d'exceptions requis, le contrôle lui passe. Si ce n'est pas le cas, la JVM recherche plus loin dans la chaîne de blocs catch jusqu'à ce que le gestionnaire approprié soit trouvé. Après l'exécution d'un bloc catch , le contrôle est transféré au bloc finally facultatif. Si une prise appropriéeblock n'est pas trouvé, la JVM arrête le programme et affiche la trace de la pile (la pile actuelle des appels de méthode), après avoir d'abord exécuté le bloc finally s'il existe. Exemple de gestion des exceptions :
public class Print {
void print(String s) {
if (s == null) {
throw new NullPointerException("Exception: s is null!");
}
System.out.println("Inside print method: " + s);
}
public static void main(String[] args) {
Print print = new Print();
List list= Arrays.asList("first step", null, "second step");
for (String s : list) {
try {
print.print(s);
}
catch (NullPointerException e) {
System.out.println(e.getMessage());
System.out.println("Exception handled. The program will continue");
}
finally {
System.out.println("Inside finally block");
}
System.out.println("The program is running...");
System.out.println("-----------------");
}
}
}
Voici les résultats de la méthode principale :
Inside print method: first step
Inside finally block
The program is running...
-----------------
Exception: s is null!
Exception handled. The program will continue
Inside finally block
The program is running...
-----------------
Inside print method: second step
Inside finally block
The program is running...
-----------------
Le finally est généralement utilisé pour fermer tous les flux et libérer toutes les ressources ouvertes/allouées dans un bloc try . Cependant, lors de l'écriture d'un programme, il n'est pas toujours possible de suivre la fermeture de toutes les ressources. Pour nous faciliter la vie, les développeurs de Java proposent la construction try-with-resources , qui ferme automatiquement toutes les ressources ouvertes dans un bloc try . Notre premier exemple peut être réécrit avec try-with-resources :
public String input() throws MyException {
String s = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))){
s = reader.readLine();
} catch (IOException e) {
System.out.println(e.getMessage());
}
if (s.equals("")) {
throw new MyException ("The string cannot be empty!");
}
return s;
}
Grâce aux fonctionnalités Java introduites dans la version 7, nous pouvons également combiner la capture d'exceptions hétérogènes en un seul bloc, ce qui rend le code plus compact et lisible. Exemple:
public String input() {
String s = null;
try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in))) {
s = reader.readLine();
if (s.equals("")) {
throw new MyException("The string cannot be empty!");
}
} catch (IOException | MyException e) {
System.out.println(e.getMessage());
}
return s;
}
GO TO FULL VERSION