Vous aimez ce que vous lisez sur ce blog ?
Envie d'aller plus loin avec véritable formation d'expertise en Java ?
Venez suivre ma formation Masterclasse Expertise Java !

"Même un développeur experimenté a besoin de continuer à apprendre. Et dans cette formation... j'ai appris beaucoup !" - A.G., Java Champion

Sessions intra-entreprises sur demande : contact[at]mokatech.net.
Inscrivez-vous vite !

Java Quiz #7

Que fait le code suivant ?

  1. public class Parser
  2. {
  3. public static int parse(String valeur)
  4. {
  5. try
  6. {
  7. return Integer.parseInt(valeur);
  8. }
  9. catch (NumberFormatException nfEx)
  10. {
  11. return 2;
  12. }
  13. finally
  14. {
  15. return 3;
  16. }
  17. }
  18.  
  19. public static void main(String... args)
  20. {
  21. System.out.println(parse("1"));
  22. System.out.println(parse("1.0"));
  23. }
  24. }

Réponse :
Ce code affiche

3
3

La spécification du langage Java montre clairement que, quel que soit le résultat des blocs try et catch, le bloc finally sera toujours exécuté, et décidera du résultat final de l'expression.

En particulier :

If the finally block completes abruptly for any reason, then the try statement completes abruptly for the same reason.

Ce qui signifie que, si le bloc finally exécute un return ou lance une exception, l'ensemble du bloc try-catch-finally se termine sur ce return ou cette exception. Conséquence : les valeurs retournées et les exceptions lancées depuis les blocs try et catch sont alors tout simplement ignorés.

Dans notre exemple :

  1. Le premier appel à notre méthode parse() est effectué avec une chaîne représentant correctement un entier. Integer.parseInt() ne génère pas d'erreur, et le return est effectué. Mais avant de rendre la main à son appelant, la méthode exécute le bloc finally associé. Celui-ci effectue un return qui "écrase" alors est alors celui du bloc try. La valeur renvoyée est donc 3.
  2. Le second appel est effectué avec une valeur qui met Integer.parseInt() en erreur. Le bloc catch est donc exécuté, et se prépare à renvoyer 2. Mais là encore le bloc finally est exécuté, et c'est encore la valeur 3 qui est renvoyée.

Conclusion : Il ne faut jamais exécuter de return ni lancer d'exceptions depuis un bloc finally !

Application pratique :
Lors de la lecture d'un fichier, le bloc finally sert à fermer le flux. Or, la méthode close() peut lever une IOException. Il est donc nécessaire de capturer cette exception pour éviter qu'elle ne soit renvoyée par le bloc finally.

  1. public static void readFile(String file)
  2. {
  3. FileReader reader = null;
  4. try
  5. {
  6. reader = new FileReader(file);
  7. // Lire le fichier
  8. }
  9. catch (IOException ioEx)
  10. {
  11. // Traiter l'exception de lecture
  12. }
  13. finally
  14. {
  15. try
  16. {
  17. if (reader != null)
  18. { reader.close();
  19. }
  20. }
  21. catch (IOException ex)
  22. {
  23. // Loguer l'exception de fermeture du flux
  24. // Il ne faut surtout pas relancer cette exception !
  25. }
  26. }
  27. }

Commentaires

1. Le lundi 7 avril 2008, 15:09 par Pierre

heu j'aurais tendance à dire :
3
3

Mais j'hésite avec une Exception à la compilation ou à l'exécution... (je vais de ce pas copier/coller le code mais je dirais rien...)

2. Le lundi 7 avril 2008, 15:18 par Pierre

mmmh ok j'ai fais le test sous eclipse et j'ai la réponse. Mais je me l'explique pas trop, vivement la réponse! :)

3. Le mercredi 9 avril 2008, 12:49 par Mialy

Est-ce qu'on n'avait pas dit un jour de ne jamais mettre de return dans un bloc finally ?

4. Le mercredi 9 avril 2008, 14:14 par Olivier Croisier

Si, justement :)
Te rappelles-tu pourquoi ?

5. Le vendredi 11 avril 2008, 13:36 par Mialy

Si je me souviens bien c'est pour garantir l'exécution de toutes les intstructions du bloc sans encombre. Avec un return ou un throw dans le bloc finally le comportement du code est imprévisible.

6. Le vendredi 11 avril 2008, 15:22 par HollyDays

NEEEEEEETTT !!!!

Le comportement de ce code est parfaitement prévisible. C'est juste qu'il est, disons... inhabituel.
Même joueur, joue encore... :-)))

7. Le lundi 14 avril 2008, 11:56 par pierre

Oue bon, mes pseudo t'ont pas plu? Je suis devenu monsieur inconnu :)

Bon, plus sérieusement, je ne comprends pas pourquoi ne pas relancer l'exception dans le finally. Si pour une raison où une autre, on ne veux pas risquer de rester avec un flux ouvert? on peut vouloir cette erreur bloquante, non?

Ajouter un commentaire

Le code HTML est affiché comme du texte et les adresses web sont automatiquement transformées.