IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

avec Java Discussion :

Gestion des exceptions


Sujet :

avec Java

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Août 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 165
    Points : 116
    Points
    116
    Par défaut Gestion des exceptions
    Bonsoir,

    je suis plutôt débutant, et j'ai des difficultés à bien comprendre comment fonctionnent les exceptions mais surtout comment et quand elles remontent au niveau au dessus.

    Exemple : imaginons une méthode static d'une classe de la DAO

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
     
    public static MyObject getMyObjbyID(....) throws IOException, ClassNotFoundException, SQLException {
     
      Connection con = null;
      Statement stmt = null;
      ResultSet result = null;
     
      MyObject curObj = null;
      try {
            con = ..... (ouverture de la connexion)
            stmt = con.createStatement();
     
            req = "SELECT.......";
            log.error(...);
     
            result = stmt.executeQuery(req);
            if (result.next()){
                String titre = result.getString("TITRE");
                ....
     
                curObj = new MyObject(...);
                return curObj;
            }
      } finally {
           ... (fermeture de la connexion)
      }
     
      return null;
    }
    j'aimerai savoir si ce genre de code est "propre", et comment cela se passe d'un point de vue exception / au bloc try...finally.

    Est ce qu'à la moindre exception, le bloc finally est executée et l'exception renvoyée par la méthode à l'étage au dessus ?
    Ou doit rajouter un bloc catch qui fera un "throw new Exception(...)" ?

    Bref quelques explications sont de rigueur

    Merci

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par Targan Voir le message
    j'aimerai savoir si ce genre de code est "propre", et comment cela se passe d'un point de vue exception / au bloc try...finally.
    Il n'est pas mal.
    Mais le return null; à la fin ne devrait pas exister. Plus exactement, cet endroit ne devrait pas être atteignable, et refusé par le compilateur, comme code mort.

    Ce qui se passe, c'est :
    - Si pas d'Exception en utilisant la BDD, quand on atteint le return, on exécute le finally (libérant ainsi la connexion), puis on quitte la méthode, et l'appelant de la méthode obtient la valeur du return.
    - Si pas d'exception, et pas de return atteint, à la fin du bloc try, on exécute le finally, puis on continue l'exécution après le bloc try/finally.

    - Si une Exception est lancée, le bloc try s'arrête, puis on exécute le finally, puis on arrête l'exécution de la méthode et on propage l'exception atteinte à la méthode appelante.

    => Autrement dit, le code finally est toujours appelé. Il est appelé quand on essaie de sortir du try (ou du catch s'il y a un catch), puis après le finally on continue comme s'il était pas là.
    Il est parfait pour tout ce qu'on ne veut pas oublier de faire, quel que soit le chemin emprunté. Comme libérer les ressources par exemple.

    Ah, important : si le finally est lui-même générateur d'une Exception, cette exception est remontée à l'appelant. Même si c'est un return ou une Exception qui nous a mené au finally.
    Normalement c'est pas ce qu'on veut, et on cherche à empêcher finally de propager ses éventuelles exceptions.

    Citation Envoyé par Targan Voir le message
    jEst ce qu'à la moindre exception, le bloc finally est executée et l'exception renvoyée par la méthode à l'étage au dessus ?
    Oui.

    Toutefois, s'il y a un catch correspondant à cette exception, le contenu du catch est exécuté avant le contenu du finally. Et l'exception ne sera remontée à l'appelant que si le code du catch dit de le faire.

    Citation Envoyé par Targan Voir le message
    Ou doit rajouter un bloc catch qui fera un "throw new Exception(...)" ?
    Non.

    Faire cela servirait si tu veux propager une autre exception que celle que tu as reçue. Par exemple pour transformer une SQLException en JAiUnProblemeAvecLaBDDException.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Août 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 165
    Points : 116
    Points
    116
    Par défaut
    Mais le return null; à la fin ne devrait pas exister. Plus exactement, cet endroit ne devrait pas être atteignable, et refusé par le compilateur, comme code mort.
    A moins que je ne dise une bêtise, ce n'est pas du code mort.
    Que se passe t il si la requete s'execute bien mais qu'aucune donnée n'est trouvée ?....le finally s'execute, puis le code continue...et donc il faudra bien un return, non ?

    D'ailleurs il me semble que sous Netbeans (je suis sous netbeans et non eclypse), il mettra un warning comme quoi y a pas de valeur de retour si je ne mets pas le return à la fin.

    Par contre, je m'apercois qu'il y a moyen de faire plus propre probablement : au lieu de mettre return null, je mets return curObj, et je vire celui qu'il y a dans le bloc try. Ainsi peu importe donnée récupérée ou non, le curObj sera renvoyé (instancié ou null).

    Qu'en penses tu ?

    merci pour ta réponse constructive, ca me parait plus clair pour la remontée/propagation de l'exception.

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 551
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 551
    Points : 21 607
    Points
    21 607
    Par défaut
    Citation Envoyé par Targan Voir le message
    A moins que je ne dise une bêtise, ce n'est pas du code mort.
    Pas forcément, en effet, mais il serait sans doute plus propre d'en faire du code mort.
    Autrement dit, de terminer tous les chemins et que cet endroit ne soit pas atteignable.

    Que se passe t il si la requete s'execute bien mais qu'aucune donnée n'est trouvée ?....le finally s'execute, puis le code continue...et donc il faudra bien un return, non ?
    Rien ne t'empêche de gérer ce cas à l'intérieur du try. Avec un return null ou une exception.
    Du coup, quand le finally s'exécute, il y a déjà eu return ou exception, et il est inutile (et inatteignable) d'en mettre un après.

    D'ailleurs il me semble que sous Netbeans (je suis sous netbeans et non eclypse), il mettra un warning comme quoi y a pas de valeur de retour si je ne mets pas le return à la fin.
    S'il y a des chemins où le return n'est pas atteint et qu'une Exception n'est pas forcément lancée, oui.
    Sinon, non. Au contraire, il refusera le code mort.

    Par contre, je m'apercois qu'il y a moyen de faire plus propre probablement : au lieu de mettre return null, je mets return curObj, et je vire celui qu'il y a dans le bloc try. Ainsi peu importe donnée récupérée ou non, le curObj sera renvoyé (instancié ou null).

    Qu'en penses tu ?
    Je pense vraiment qu'il est préférable que le return soit atteint avant le finally.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par Targan Voir le message
    j'aimerai savoir si ce genre de code est "propre",
    Personnellement plusieurs choses me chagrine :
    • Les variables locales définies en début de méthode... C'est du Java pas du C !!!
    • L'ouverture de la connection dans le try/finally, alors que cela devrait être juste avant.
    • Et d'une moindre mesure les autres ressources (Statement et ResultSet) qui ne sont pas libérés via un try/finally.


    Après il y aurait peut-être d'autres choses, mais comme le code est rempli de "..." ce n'est pas forcément évident à dire...

    Pour ma part cela ressemblerais plutôt à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    	public static MyObject getMyObjbyID(...) throws IOException, ClassNotFoundException, SQLException {
     
    		Connection con = null;
    		try {
    			Statement stmt = ...
    			try {
    				String req = "SELECT.......";
    				log.error(...);
     
    				ResultSet result = stmt.executeQuery(req);
    				try {
    					if (result.next()) {
    						String titre = result.getString("TITRE");
    						// ....
     
    						MyObject curObj = new MyObject(...);
    						return curObj;
    					}
    					return null;
    				} finally {
    					result.close();
    				}
    			} finally {
    				stmt.close();
    			}
    		} finally {
    			con.close();
    		}
    	}
    Les multiples try/finally sont peut-être un peu lourd, mais c'est bien plus propre dans le cas où on effectuerait plusieurs requêtes...



    Citation Envoyé par Targan Voir le message
    Est ce qu'à la moindre exception, le bloc finally est executée et l'exception renvoyée par la méthode à l'étage au dessus ?
    Dès que tu rentres dans un bloc try, le finally correspondant sera exécuté dans tous les cas (fin du bloc, throw exception ou return), tout en laissant continuer le traitement normalement :
    • En cas de fin du bloc normale, le traitement de la méthode continuera.
    • En cas d'exception, elle sera remontée.
    • En cas de return, la valeur sera renvoyé.


    Il y a deux cas particulier :
    • Si le bloc finally génère une exception, cette dernière sera remonté quoi qu'il arrive.
    • Si le bloc finally effectue un return, cette valeur sera retourné (mais c'est une mauvaise pratique généralement signalé par les compilateur)



    Citation Envoyé par thelvin Voir le message
    Je pense vraiment qu'il est préférable que le return soit atteint avant le finally.
    +1

    Ou au moins (si on n'aime pas trop cette structure) de limiter le return à un seul endroit : soit à l'intérieur du try, soit après le finally (mais pas les deux à la fois)


    a++

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Août 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 165
    Points : 116
    Points
    116
    Par défaut
    Personnellement plusieurs choses me chagrine :

    * Les variables locales définies en début de méthode... C'est du Java pas du C !!!
    * L'ouverture de la connection dans le try/finally, alors que cela devrait être juste avant.
    * Et d'une moindre mesure les autres ressources (Statement et ResultSet) qui ne sont pas libérés via un try/finally.
    Je ne piges pas vraiment la 1ere remarque.
    Faut bien "déclarer" ou "initialiser" les variables, tu le ferais où sinon ?
    Tu ne mettrais rien, et récupèrerai directement l'instance ? genre ResultSet direct en recup de l'executeQuery ?

    Pour ce qui est de la suite, c'est géré directement dans ce que j'appelais ouverture de connex / fermeture qui close TOUT.

    Donc globalement, sortir le return pour le mettre en fin du try et uniquement là serait la solution la plus propre ?

    genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
     
    public static MyObject getMyObjbyID(....) throws IOException, ClassNotFoundException, SQLException {
      try {
            MyObject curObj = null;
            con = ..... (ouverture de la connexion)
            stmt = con.createStatement();
     
            req = "SELECT.......";
            log.error(...);
     
            result = stmt.executeQuery(req);
            if (result.next()){
                String titre = result.getString("TITRE");
                ....
     
                curObj = new MyObject(...);
            }
            return curObj;
      } finally {
           ... (fermeture de la connexion)
      }
    }

    merci

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Targan Voir le message
    Je ne piges pas vraiment la 1ere remarque.
    Faut bien "déclarer" ou "initialiser" les variables, tu le ferais où sinon ?
    Tu ne mettrais rien, et récupèrerai directement l'instance ? genre ResultSet direct en recup de l'executeQuery ?
    Ben j'ai publié un code : je déclare les variables lorsque je les utilises...

    Citation Envoyé par Targan Voir le message
    Pour ce qui est de la suite, c'est géré directement dans ce que j'appelais ouverture de connex / fermeture qui close TOUT.
    Tu ne fermes pas explicitement le Statement ni le ResultSet. C'est mieux de le faire...


    a++

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Août 2007
    Messages
    165
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2007
    Messages : 165
    Points : 116
    Points
    116
    Par défaut
    ben si j'ai dit que la fonction appelée dans le finally closait TOUT

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    public static void closeConnection(Connection con, Statement, stmt, ResultSet resultset) throws SQLException {
      try {
          if (result != null) {
              result.close();
          }
      } finally {
          try {
              if (stmt != null) {
                  stmt.close();
              } 
          } finally {
              if (con != null) {
                  con.close();
              } 
          }   
      }
    }

  9. #9
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Comme je l'ai dit ce n'était pas explicite dans ton code... et on ne peut se baser que là dessus pour critiquer un code



    Quand à ta méthode closeConnection(), elle ferme tout ou rien.
    Je ne trouve pas cela pratique car cela implique de changer de pattern selon les cas. Par exemple si tu effectues plusieurs requêtes sur la même connexion, tu devras utiliser des try/finally pour fermer certains Statement/ResultSet, et ta méthode closeConnection() pour d'autre...


    Je préfère ne pas me poser de question et utiliser le pattern "1 try/finally par ressource" dans tous les cas... en attendant Java 7 !


    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [ADOConnect] gestion des exception en tout temps
    Par portu dans le forum Bases de données
    Réponses: 1
    Dernier message: 20/04/2005, 19h01
  2. [ORACLE 9i] Gestion des exceptions
    Par sygale dans le forum SQL
    Réponses: 6
    Dernier message: 19/08/2004, 15h06
  3. Gestion des exception (EOleException)
    Par shurized dans le forum Bases de données
    Réponses: 5
    Dernier message: 30/06/2004, 17h25
  4. [XMLRAD] gestion des exceptions
    Par pram dans le forum XMLRAD
    Réponses: 2
    Dernier message: 28/01/2003, 17h48
  5. c: gestion des exceptions
    Par vince_lille dans le forum C
    Réponses: 7
    Dernier message: 05/06/2002, 14h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo