1. Découverte du bloc finally
Lorsque vous travaillez avec des ressources — fichiers, connexions réseau, bases de données — il est important d’être certain qu’elles seront fermées ou libérées toujours, même si une erreur survient pendant l’exécution. En Java, il existe pour cela un bloc spécial — finally.
Comment fonctionne finally ?
Le bloc finally fait partie de la construction try-catch-finally. Le code à l’intérieur de finally s’exécute toujours (s’il est présent) — qu’il y ait eu une exception ou non. Même s’il y a un return dans try ou qu’une exception est levée, finally s’exécutera quand même (sauf si l’ordinateur est éteint ou si le programme est terminé de force via System.exit(0)).
Syntaxe :
try {
// Code susceptible de lever une exception
} catch (ExceptionType e) {
// Traitement de l'erreur
} finally {
// Ce code s'exécutera toujours !
}
Exemple
try {
System.out.println("Début de l'exécution");
int result = 10 / 0; // une erreur va se produire ici
System.out.println("Résultat: " + result);
} catch (ArithmeticException e) {
System.out.println("Erreur: division par zéro");
} finally {
System.out.println("Ce code s'exécutera dans tous les cas");
}
Résultat de l’exécution :
Début de l'exécution
Erreur: division par zéro
Ce code s'exécutera dans tous les cas
Que se passe-t-il ?
- Dans try, nous tentons de diviser deux nombres et obtenons une erreur.
- Si une erreur survient lors de la division — catch la traite.
- Mais ! Quoi qu’il arrive, finally s’exécute et écrit un message dans la console.
2. finally sans catch
Il peut y avoir 3 variantes de la construction :
- Complète : try-catch-finally
- Sans finally : try-catch
- Sans catch : try-finally
La troisième variante est utilisée quand la capture et le traitement de l’erreur seront effectués par une méthode de niveau supérieur. Mais le bloc finally est nécessaire pour garantir l’exécution d’un certain code :
- Fermeture de fichiers, connexions réseau, bases de données.
- Libération de toute ressource (par exemple, des verrous).
- Journalisation : consigner des informations sur la fin de l’opération.
Exemple :
try {
System.out.println("On divise des nombres");
int result = 10 / 0; // erreur !
System.out.println("Résultat: " + result);
} finally {
System.out.println("Le bloc finally a été exécuté");
}
Résultat :
On divise des nombres
Le bloc finally a été exécuté
Exception in thread "main" java.lang.ArithmeticException: / by zero
Quand finally NE s’exécute-t-il pas ?
Il s’exécute presque toujours. Exceptions — si :
- Le programme a été terminé de force via : System.exit(0).
- Le thread dans lequel s’exécute finally a été « tué » de force.
- L’ordinateur a été éteint.
3. L’opérateur throw : comment générer une exception soi-même
Parfois, Java « lève » elle-même des exceptions (par exemple, division par zéro, dépassement des limites d’un tableau). Mais il existe des situations où vous souhaitez signaler explicitement : « C’est une erreur ! Je ne peux pas continuer l’exécution ! ». Pour cela, Java fournit l’opérateur throw.
Analogie : Si vous êtes dans un magasin et voyez un produit périmé — vous déposez une réclamation. De même dans le code : si quelque chose ne va pas — vous levez une exception.
Syntaxe de throw
throw new ExceptionType("Message d'erreur");
ExceptionType — toute classe dérivant de Throwable (généralement Exception ou RuntimeException). Entre parenthèses, un message qui aide à comprendre ce qui s’est mal passé.
Exemple : validation des arguments d’une méthode
public static int safeDivide(int a, int b) {
if (b == 0) {
throw new IllegalArgumentException("Le diviseur ne peut pas être égal à zéro");
}
return a / b;
}
Utilisation :
public static void main(String[] args) {
try {
int result = safeDivide(10, 0);
System.out.println("Résultat: " + result);
} catch (IllegalArgumentException e) {
System.out.println("Erreur: " + e.getMessage());
}
}
Résultat :
Erreur: Le diviseur ne peut pas être égal à zéro
Quand utiliser throw ?
- Validation des arguments d’une méthode (par exemple, si null est passé ou si les données sont incorrectes).
- Vérification de l’état d’un objet (par exemple, tentative de retirer de l’argent d’un compte qui contient 0 €).
- À l’intérieur de catch — si vous souhaitez « relancer » l’exception plus loin (par exemple, pour ajouter des informations supplémentaires).
4. Combiner try-catch-finally et throw
Parfois, ces constructions fonctionnent ensemble. Par exemple, vous interceptez une erreur, puis décidez d’en lever une autre, plus informative.
public static int parseAndDivide(String text, int divisor) {
try {
int number = Integer.parseInt(text);
if (divisor == 0) {
throw new IllegalArgumentException("Le diviseur ne peut pas être égal à zéro");
}
return number / divisor;
} catch (NumberFormatException e) {
throw new IllegalArgumentException("La chaîne '" + text + "' n'est pas un nombre");
} finally {
System.out.println("Tentative de traiter la chaîne: " + text);
}
}
Utilisation :
try {
int result = parseAndDivide("42a", 2);
System.out.println("Résultat: " + result);
} catch (IllegalArgumentException e) {
System.out.println("Erreur: " + e.getMessage());
}
Résultat :
Tentative de traiter la chaîne: 42a
Erreur: La chaîne '42a' n'est pas un nombre
Nuance importante : return et finally
Même s’il y a un return dans le bloc try, finally s’exécutera quand même !
public static int getValue() {
try {
return 10;
} finally {
System.out.println("finally s'exécutera quand même !");
}
}
L’appel à getValue() affichera :
finally s'exécutera quand même !
5. Erreurs courantes lors de l’utilisation de finally et throw
Erreur n° 1 : oublier de fermer une ressource sans finally.
Problème très fréquent : on ouvre un fichier, on ne le referme pas — fuite de ressources. Utilisez toujours finally (ou try-with-resources, dont nous parlerons plus tard).
Erreur n° 2 : lever une exception sans la traiter.
Si vous levez une exception avec throw mais que vous ne la capturez nulle part (pas de try-catch), le programme s’arrêtera brutalement. Réfléchissez toujours à qui va capturer votre exception.
Erreur n° 3 : return dans finally.
Si vous avez écrit par erreur un return à l’intérieur de finally, il « éclipsera » tous les return ou throw précédents. Cela peut entraîner des bogues très difficiles à détecter. C’est fortement déconseillé !
public int tricky() {
try {
return 1;
} finally {
return 2; // DANGEREUX: 2 sera renvoyé, pas 1 !
}
}
Résultat : 2 sera renvoyé, alors que dans try il y avait 1.
Erreur n° 4 : perte d’information sur l’exception.
Si vous capturez une exception, puis en levez une nouvelle sans conserver les informations sur l’ancienne (e), vous perdez la pile d’appels, ce qui complique le débogage. Il vaut mieux écrire :
catch (NumberFormatException e) {
throw new IllegalArgumentException("Erreur de conversion", e);
}
GO TO FULL VERSION