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 #30

Ah, cela faisait longtemps que je ne vous avais pas proposé de quiz !
En voici un simple qui devrait vous distraire en ce jour pluvieux.

Quel est le problème avec cette méthode très classique ?

  1. /**
  2.  * Affiche le fichier texte passé en paramètre.
  3.  * Les commentaires indiquent les exceptions potentiellement levées
  4.  */
  5. public void displayFile(String fileName) throws IOException {
  6. BufferedReader br = null;
  7. try {
  8. br = new BufferedReader(new FileReader(fileName)); // FileNotFoundException
  9. String line = null;
  10. while ((line=br.readLine()) != null) { // IOException
  11. System.out.println(line);
  12. }
  13. } catch (Exception e) {
  14. e.printStackTrace();
  15. throw e;
  16. } finally {
  17. if (br != null) {
  18. br.close(); // IOException
  19. }
  20. }
  21. }

Note : j'ai corrigé le problème du "close() pas dans un bloc finally" qui distrayait les lecteurs du véritable problème de ce bout de code.

Réponse :
Ce code ne compile pas à cause du type de l'exception relancée depuis le bloc "catch".

En effet, la signature de la méthode signale une possible IOException, alors que nous lançons une Exception, plus générique, depuis le bloc "catch".

Nous avons donc deux solutions pour corriger cette erreur :

  • Modifier la signature de la méthode pour qu'elle déclare une Exception ; mais ce serait évidemment peu satisfaisant, car il faut toujours manipuler les exceptions les plus précises possibles.
  • Modifier le bloc catch pour captuter une simple IOException, ou, encore mieux, une FileNotFoundException et une IOException, afin de réagir finement en cas de problème.

En tout cas, félicitations à tous les lecteurs qui ont rapidement résolu ce quiz !


Commentaires

1. Le mardi 1 décembre 2009, 14:25 par Nicolas

Ca envoit n'importe quelles exception alors qu'on ne sont déclarées que l'envoi de IOException.
De plus, le bufferreader n'est pas fermé en cas d'erreur de lecture.

2. Le mardi 1 décembre 2009, 14:28 par PierreMage

...throws IOException {
...catch (Exception e) {
... throw e;

3. Le mardi 1 décembre 2009, 15:11 par FlorentCappelle

Il me semble aussi que ça peut boucler à l’infini avec un fichier qui ne se termine pas par un caractère de terminaison (en tout cas c’est le cas avec le flux System.in).

4. Le mardi 1 décembre 2009, 15:55 par Benoît

Dans le cas nominal, la méthode close est encore appelée deux fois sur br.

Cela dit, le problème est que e est type comme étant une "Exception", alors que la clause throws de la méthode displayFile ne déclare que des IOException.

5. Le mercredi 2 décembre 2009, 09:48 par HollyDays

Hé, hé... L'initialisation de "line" à "null" est inutile. Comment ça, ça n'est pas un problème ?!? Bon OK... moi je dis : c'est l'exception qui confirme la règle ! ;-)

6. Le jeudi 3 décembre 2009, 13:57 par Piwaï

@HollyDays : il me semble que l'init à null est obligatoire, sous peine de ne pas compiler à la ligne 17.

Je rejoins #1, #2 et #4 sur l'exception. Le code jette potentiellement une exception de type Exception à la ligne 15, qui n'est ni catchée ni déclarée.

A la ligne 18, le code bien écrit devrait plutôt être :

if (br != null) {

 try {
   br.close();
 } catch(IOException e) {} //Eventuellement un log

}

Le fait que le close se soit mal passé ne devrait pas nécessairement interrompre le fonctionnement normal de l'application.

7. Le jeudi 3 décembre 2009, 14:10 par Benoît

@Piwaï
Le fait que le close se soit mal passé ne devrait pas nécessairement interrompre le fonctionnement normal de l'application.

Très bonne remarque, je plussois.

8. Le jeudi 3 décembre 2009, 16:05 par hadf

On reporte une exception de type Exception alors que seules les exceptions de type IOException sont déclarées dans la signature de la méthode. Ca ne passe pas à la compil.

9. Le samedi 5 décembre 2009, 12:26 par HollyDays

@ Piwaï
En effet, la variable "br" doit effectivement être initialisé à "null" sous peine de ne pas compiler. Mais ma remarque ne portait pas sur cette variable-là : elle concernait la variable "line". Qui, je le confirme, n'a pas besoin d'être initialisée à "null" ici (vous pouvez vérifier avec le compilateur).

Sinon, pour ceux qui l'ont comprise, mon allusion («c'est l'exception qui confirme la règle ! ;-)») faisait effectivement référence (sic) à l'exception jetée par cette fonction.

10. Le lundi 7 décembre 2009, 16:41 par Lepnio

Ca ne gène personne que le FileReader qui est un flux ne soit jamais fermé.

11. Le lundi 7 décembre 2009, 16:43 par Lepnio

Je retire ... le buffredReader s'en occupe quand on le close.

12. Le vendredi 11 décembre 2009, 10:55 par regis

Le probleme est au niveau du throw

catch (Exception e) {

 e.printStackTrace();
 throw e;

}

La definition de la methode ne permet de ne lever que des exceptions de Type IOException, il faudrait juste changer la signature de la methode par

public void displayFile(String fileName) throws Exception

13. Le lundi 14 décembre 2009, 13:41 par Piwaï

@HollyDays Ok pour la variable "line" :-)

@regis
Je suppose que c'est une blague :-) . Changer la signature de la méthode, c'est se tirer une balle... J'espère que personne ne développe comme ça ;-) . Mieux vaut modifier ligne 13, Exception en IOException ;-) .

14. Le lundi 14 décembre 2009, 23:16 par Olivier Croisier

@Piwaï : Oui, il vaut toujours mieux utiliser les exceptions les plus précises. Le must serait même de capturer séparément FileNotFoundException et IOException - mais comme leur traitement est commun ici, en attendant les multi-catch de Java7, on se satisfera de la capture de IOException.

Ajouter un commentaire

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