Salut! Je déteste le mentionner, mais une grande partie du travail d'un programmeur consiste à gérer les erreurs. Le plus souvent, le sien. Il s'avère qu'il n'y a pas de gens qui ne font pas d'erreurs. Et il n'y a pas non plus de tels programmes. Bien sûr, face à une erreur, l'essentiel est de comprendre sa cause. Et beaucoup de choses peuvent causer des bogues dans un programme. À un moment donné, les créateurs de Java se sont demandé ce qu'il fallait faire des erreurs de programmation les plus probables ? Les éviter complètement n'est pas réaliste, les programmeurs sont capables d'écrire des choses que vous ne pouvez même pas imaginer. :) Donc, nous devons donner au langage un mécanisme pour travailler avec les erreurs. En d'autres termes, s'il y a une erreur dans votre programme, vous avez besoin d'une sorte de script pour savoir quoi faire ensuite. Que doit faire exactement un programme lorsqu'une erreur se produit ? Aujourd'hui, nous allons nous familiariser avec ce mécanisme. Cela s'appelle " des exceptions en Java ".
Qu'est-ce qu'une exception ?
Une exception est une situation exceptionnelle et imprévue qui se produit pendant l'exécution d'un programme. Il existe de nombreuses exceptions. Par exemple, vous avez écrit du code qui lit le texte d'un fichier et affiche la première ligne.
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
}
}
Mais que se passe-t-il s'il n'y a pas un tel fichier ! Le programme va générer une exception : FileNotFoundException
. Sortie : Exception dans le thread "main" java.io.FileNotFoundException : C:\Users\Username\Desktop\test.txt (Le système ne trouve pas le chemin spécifié) En Java, chaque exception est représentée par une classe distincte. Toutes ces classes d'exception dérivent d'un "ancêtre" commun - la Throwable
classe parent. Le nom d'une classe d'exception reflète généralement de manière concise pourquoi l'exception s'est produite :
FileNotFoundException
(le fichier n'a pas été trouvé)ArithmeticException
(une exception s'est produite lors de l'exécution d'une opération mathématique)ArrayIndexOutOfBoundsException
(l'index est au-delà des limites du tableau). Par exemple, cette exception se produit si vous essayez d'afficher la position 23 d'un tableau qui ne contient que 10 éléments.
Exception in thread "main"
Euhhh. :/ Cela n'aide pas beaucoup. On ne sait pas ce que signifie l'erreur ni d'où elle vient. Il n'y a pas d'informations utiles ici. Mais la grande variété de classes d'exceptions en Java donne au programmeur ce qui compte le plus : le type d'erreur et sa cause probable (intégrée dans le nom de la classe). C'est tout autre chose à voir
Exception in thread "main" java.io.FileNotFoundException: C:\Users\Username\Desktop\test.txt (The system cannot find the specified path)
Il est immédiatement clair quel pourrait être le problème et où commencer à creuser pour résoudre le problème ! Les exceptions, comme les instances de toutes les classes, sont des objets.
Capture et gestion des exceptions
Java a des blocs de code spéciaux pour travailler avec des exceptions :try
, catch
et finally
. Le code où le programmeur pense qu'une exception peut se produire est placé dans le try
bloc. Cela ne signifie pas qu'une exception se produira ici. Cela signifie que cela pourrait se produire ici, et le programmeur est conscient de cette possibilité. Le type d'erreur que vous attendez est placé dans le catch
bloc. Celui-ci contient également tout le code qui doit être exécuté si une exception se produit. Voici un exemple :
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
}
}
Sortie : Erreur ! Fichier introuvable! Nous mettons notre code en deux blocs. Dans le premier bloc, nous prévoyons qu'une erreur "Fichier introuvable" peut se produire. C'est le try
bloc. Dans le second, nous indiquons au programme ce qu'il doit faire si une erreur se produit. Et le type d'erreur spécifique : FileNotFoundException
. Si nous mettons une classe d'exception différente entre les parenthèses du catch
bloc, alors FileNotFoundException
nous ne serons pas interceptés.
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (ArithmeticException e) {
System.out.println("Error! File not found!");
}
}
Sortie : Exception dans le thread "main" java.io.FileNotFoundException : C:\Users\Username\Desktop\test.txt (Le système ne peut pas trouver le chemin spécifié) Le code dans le catch
bloc n'a pas été exécuté, car nous avons "configuré" ce bloc pour attraper ArithmeticException
, et le code dans le try
bloc a jeté un type différent : FileNotFoundException
. Nous n'avons pas écrit de code pour gérer FileNotFoundException
, donc le programme affiche les informations par défaut pour FileNotFoundException
. Ici, vous devez faire attention à trois choses. Numéro un. Une fois qu'une exception se produit sur une ligne du try
bloc, le code qui suit ne sera pas exécuté. L'exécution du programme "saute" immédiatement au catch
bloc. Par exemple:
public static void main(String[] args) {
try {
System.out.println("Divide by zero");
System.out.println(366/0);// This line of code will throw an exception
System.out.println("This");
System.out.println("code");
System.out.println("will not");
System.out.println("be");
System.out.println("executed!");
} catch (ArithmeticException e) {
System.out.println("The program jumped to the catch block!");
System.out.println("Error! You can't divide by zero!");
}
}
Sortie : Diviser par zéro Le programme est passé au bloc catch ! Erreur! Vous ne pouvez pas diviser par zéro ! Sur la deuxième ligne du try
bloc, nous essayons de diviser par 0, ce qui donne un ArithmeticException
. Par conséquent, les lignes 3 à 9 du try
bloc ne seront pas exécutées. Comme nous l'avons dit, le programme commence immédiatement à exécuter le catch
bloc. Numéro deux. Il peut y avoir plusieurs catch
blocs. Si le code dans le try
bloc peut générer non pas un, mais plusieurs types d'exceptions différents, vous pouvez écrire un catch
bloc pour chacun d'eux.
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
System.out.println(366/0);
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
} catch (ArithmeticException e) {
System.out.println("Error! Division by 0!");
}
}
Dans cet exemple, nous avons écrit deux catch
blocs. Si a FileNotFoundException
se produit dans le try
bloc, alors le premier catch
bloc sera exécuté. Si un ArithmeticException
se produit, le deuxième bloc sera exécuté. Vous pouvez écrire 50 catch
blocs si vous le souhaitez. Bien sûr, il vaut mieux ne pas écrire de code qui pourrait déclencher 50 types d'exceptions différentes. :) Troisième. Comment savez-vous quelles exceptions votre code peut générer ? Eh bien, vous pourrez peut-être en deviner certains, mais il vous est impossible de tout garder dans votre tête. Le compilateur Java connaît donc les exceptions les plus courantes et les situations dans lesquelles elles peuvent se produire. Par exemple, si vous écrivez du code dont le compilateur sait qu'il peut lever deux types d'exceptions, votre code ne sera pas compilé tant que vous ne les aurez pas gérées. Nous en verrons des exemples ci-dessous. Maintenant, quelques mots sur la gestion des exceptions. Il existe 2 façons de gérer les exceptions. Nous avons déjà rencontré le premier : la méthode peut gérer elle-même l'exception dans un catch()
bloc. Il existe une deuxième option : la méthode peut relancer l'exception dans la pile des appels. Qu'est-ce que cela signifie? Par exemple, nous avons une classe avec la même printFirstString()
méthode, qui lit un fichier et affiche sa première ligne :
public static void printFirstString(String filePath) {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
}
À l'heure actuelle, notre code ne compile pas, car il contient des exceptions non gérées. À la ligne 1, vous spécifiez le chemin d'accès au fichier. Le compilateur sait qu'un tel code pourrait facilement produire un fichier FileNotFoundException
. À la ligne 3, vous lisez le texte du fichier. Ce processus pourrait facilement entraîner une IOException
(erreur d'entrée/sortie). Maintenant, le compilateur vous dit : "Mec, je n'approuverai pas ce code et je ne le compilerai pas tant que vous ne m'aurez pas dit ce que je dois faire si l'une de ces exceptions se produit. Et elles pourraient certainement se produire en fonction du code que vous avez écrit. !" Impossible de contourner le problème : il faut gérer les deux ! Nous connaissons déjà la première méthode de gestion des exceptions : nous devons mettre notre code dans un try
bloc et ajouter deux catch
blocs :
public static void printFirstString(String filePath) {
try {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error, file not found!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("File input/output error!");
e.printStackTrace();
}
}
Mais ce n'est pas la seule option. Nous pourrions simplement lancer l'exception plus haut au lieu d'écrire du code de gestion des erreurs dans la méthode. Ceci est fait en utilisant le mot-clé throws
dans la déclaration de méthode :
public static void printFirstString(String filePath) throws FileNotFoundException, IOException {
BufferedReader reader = new BufferedReader(new FileReader(filePath));
String firstString = reader.readLine();
System.out.println(firstString);
}
Après le mot-clé throws
, nous indiquons une liste séparée par des virgules de tous les types d'exceptions que la méthode pourrait lever. Pourquoi? Maintenant, si quelqu'un veut appeler la printFirstString()
méthode dans le programme, il ou elle (pas vous) devra implémenter la gestion des exceptions. Par exemple, supposons qu'ailleurs dans le programme, l'un de vos collègues ait écrit une méthode qui appelle votre printFirstString()
méthode :
public static void yourColleagueMethod() {
// Your colleague's method does something
//...and then calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Nous obtenons une erreur ! Ce code ne compilera pas ! Nous n'avons pas écrit de code de gestion des exceptions dans la printFirstString()
méthode. En conséquence, cette tâche incombe désormais à ceux qui utilisent la méthode. En d'autres termes, la methodWrittenByYourColleague()
méthode a maintenant les 2 mêmes options : elle doit soit utiliser un try-catch
bloc pour gérer les deux exceptions, soit les relancer.
public static void yourColleagueMethod() throws FileNotFoundException, IOException {
// The method does something
//...and then calls your printFirstString() method with the file it needs
printFirstString("C:\\Users\\Henry\\Desktop\\testFile.txt");
}
Dans le second cas, la méthode suivante dans la pile des appels, celle qui appelle methodWrittenByYourColleague()
, devra gérer les exceptions. C'est pourquoi nous appelons cela "lancer ou transmettre l'exception". Si vous lancez des exceptions vers le haut en utilisant le mot-clé throws
, votre code sera compilé. À ce stade, le compilateur semble dire : "D'accord, d'accord. Votre code contient un tas d'exceptions potentielles, mais je vais le compiler. Mais nous reviendrons à cette conversation !" Et lorsque vous appelez une méthode qui a des exceptions non gérées, le compilateur remplit sa promesse et vous les rappelle à nouveau. Enfin, nous parlerons du finally
bloc (désolé pour le jeu de mots). C'est la dernière partie du try-catch-finally
triumvirat de gestion des exceptions..
public static void main(String[] args) throws IOException {
try {
BufferedReader reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
System.out.println("Error! File not found!");
e.printStackTrace();
} finally {
System.out.println ("And here's the finally block!");
}
}
Dans cet exemple, le code à l'intérieur du finally
bloc sera exécuté dans les deux cas. Si le code du try
bloc est exécuté en entier sans lever d'exceptions, le finally
bloc s'exécutera à la fin. Si le code à l'intérieur du try
bloc est interrompu par une exception et que le programme saute au catch
bloc, le finally
bloc s'exécutera toujours après le code à l'intérieur du catch
bloc. Pourquoi est-ce nécessaire ? Son but principal est d'exécuter du code obligatoire : du code qui doit être exécuté quelles que soient les circonstances. Par exemple, cela libère souvent certaines ressources utilisées par le programme. Dans notre code, nous ouvrons un flux pour lire les informations du fichier et les transmettre à l' BufferedReader
objet. Nous devons fermer notre lecteur et libérer les ressources. Cela doit être fait quoi qu'il arrive, quand le programme fonctionne comme il se doit et quand il lève une exception. Le finally
bloc est un endroit très pratique pour faire ceci :
public static void main(String[] args) throws IOException {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader("C:\\Users\\Username\\Desktop\\test.txt"));
String firstString = reader.readLine();
System.out.println(firstString);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
System.out.println ("And here's the finally block!");
if (reader != null) {
reader.close();
}
}
}
Maintenant, nous sommes certains que nous prendrons soin des ressources, indépendamment de ce qui se passe lorsque le programme est en cours d'exécution. :) Ce n'est pas tout ce que vous devez savoir sur les exceptions. La gestion des erreurs est un sujet très important en programmation. De nombreux articles lui sont consacrés. Dans la leçon suivante, nous verrons quels types d'exceptions existent et comment créer vos propres exceptions. :) À plus tard!
Plus de lecture : |
---|
GO TO FULL VERSION