mars
2011
Joseph Darcy a mis les choses au clair concernant les récentes annonces de la conférences Devoxx et leurs conséquences pour le projet Coin.
Et la bonne nouvelle vient du fait que la proposition d’amélioration de la gestion des exceptions est actuellement réexaminée pour une éventuelle inclusion dans Java 7, en plus des précédentes modifications déjà acceptées. Par contre il ne devrait plus y avoir de réexamen d’autre proposition…
Pour rappel, l’amélioration de la gestion des exceptions comporte deux concepts : multi-catch et rethrow.
Mais voyons voir de plus près cette proposition…
multi-catch
Le multi-catch permet tout simplement de regrouper le traitement des exceptions en un seul et même bloc.
Actuellement, lorsqu’on souhaite utiliser le même traitement pour deux types d’exception distinct, on a deux solutions :
- Soit on duplique les catch, ce qui peut s’avérer rapidement très lourd :
try {
// CODE
} catch (IOException e) {
// TRAITEMENTS
} catch (SQLException e) {
// TRAITEMENTS
} - Soit on utilise un type d’exception plus générique, mais on se retrouve alors à intercepter également des exceptions non-souhaitées, et qu’il aurait été préférable de faire remonter :
try {
// CODE
} catch (Exception e) { // intercepte toute les exceptions
// TRAITEMENTS
}
Désormais, avec le multi-catch il sera possible de d’utiliser plusieurs types sur un même catch :
try {
// CODE
} catch (final IOException|SQLException e) {
// TRAITEMENTS
}
L’intérêt étant de pouvoir cibler avec précision les exceptions que l’ont doit traiter, et donc celles que l’on doit ignorer et laisser remonter car on n’a aucune solution de contournement.
rethrow
L’objectif du rethrow est de permettre d’intercepter une exception tout en la laissant remonter, par exemple si l’on souhaite uniquement se contenter de logger.
Par exemple :
public void method() throws IOException {
try {
// CODE qui peut remonter une IOException
} catch (final Exception e) {
logger.log(e);
throw e;
}
}
Actuellement ce code provoque une erreur, car le compilateur considère que le type de l’exception remontée par le bloc catch peut être de n’importe quel type héritant d’exception, et donc la signature de la méthode devrait être revu en conséquence (ici déclarant la méthode avec throws Exception).
Le rethrow permettra dans ce cas au compilateur d’analyser le code du bloc catch, pour mieux déterminé les types réels pouvant être remontés par le code du bloc try, et donc d’éviter d’augmenter artificiellement la déclaration du throws
Remarque : dans tous les cas, le multi-catch et le rethrow implique l’utilisation du mot-clef final dans la déclaration du type du bloc catch, afin que le compilateur puisse contrôler les types d’exceptions possible sans que le développeurs ne puissent modifier cela.
[edit] Finalement le mot-clef final est devenu implicite et n’est donc pas obligatoire.
13 Commentaires + Ajouter un commentaire
Tutoriels
Discussions
- jre 1.5, tomcat 6.0 et multi processeurs
- Difference de performances Unix/Windows d'un programme?
- Définition exacte de @Override
- Classes, méthodes private
- L'apparition du mot-clé const est-il prévu dans une version à venir du JDK?
- Recuperation du nom des parametres
- [ fuite ] memoire
- Possibilité d'accéder au type générique en runtime
- [REFLEXION] Connaitre toutes les classes qui implémentent une interface
Le rethrow utilise le mot-clé « throw« , et il est applicable à tout bloc catch() (multicatch ou pas) du moment que la référence de l’exception n’est pas réaffecté (implicitement final donc).
En fait ce n’est pas réellement une nouveauté en soit mais une amélioration du rethrow existant.
En effet il est déjà possible de faire ceci :
Or actuellement il est impossible de faire un catch générique pour cela, en utilisant Exception ou Throwable :
Car le compilateur gère le throw de manière basique, et considère que la méthode doit déclarée l’exception à remonter (sauf pour les RuntimeException/Error)
Ici comme t est déclaré en Throwable
Or en analysant bien le code, le compilateur peut affiner le type de t. On sait que cela ne peut être uniquement une IOException ou une RuntimeException/Error. Donc le compilateur peut autoriser un tel code.
En fait tout cela n’est qu’une limitation liés aux checked-exceptions.
a++
Si les réponses sont « non » et « oui », je sens la confusion à la lecture d’un source.
A l’heure actuelle en effet ! C’est justement le gros problème du rethrow
a++
En effet je vois mieux l’intérêt du rethrow s’il est un impératif pour le multicatch ! Je pensais que c’était à part.
>Mais là on ne les traite pas : on se contente d’y jeter un coup d’oeil au >passage. Les exceptions sont remontées tel quel à la classe appelante, comme si >tu n’avais pas utilisé de catch…
>> Si ce n’est que la signature de ta méthode qui fait ça précise un throws Exception ce qui est assez crado (bien sûr là je parle à l’heure actuelle sans rethrow)
Le rethrow est également un impératif pour le multicatch, puisque lorsque tu fais ceci :
L’exception e est du premier type parent commun aux deux types, donc Exception dans ce cas. Et donc sans rethrow amélioré cela t’obligerait à déclarer remonter une Exception.
Pour revenir au catch(Exception) ou au catch(Throwable), c’est vrai que c’est généralement une erreur de les utiliser pour traiter l’exception.
Mais là on ne les traite pas : on se contente d’y jeter un coup d’oeil au passage. Les exceptions sont remontées tel quel à la classe appelante, comme si tu n’avais pas utilisé de catch…
a++
Je suis d’accord sur l’intérêt de loguer au passage avant de laisser remonter. Par contre je milite contre l’utilisation d’un catch(Exception e) ou catch(Throwable t). Il est beaucoup plus propre de catcher chaque exception à gérer. En attendant le multi catch il faut effectivement faire plus blocs catch mais c’est pas non plus la mer à boire. Certains disent que ça alourdit le code, moi je dis que ça en améliore la lisibilité étant donné qu’on voit clairement quels types d’exceptions sont susceptibles d’arriver…
Je maintiens que le rethrow n’est qu’une bidouille pour ceux qui utilisent les catch « globaux » qui sont pour moi à bannir d’un code de qualité.
mccabbe : L’intérêt est justement de laisser remonter les exceptions, tout en permettant quand même d’y jeter un coup d’oeil !
En clair : tu laisses remonter les exceptions, mais tu les interceptes au passage…
Dans l’exemple, l’intérêt est de logger les erreurs dans un fichier de log plus spécifique, avant de remonter l’exception à l’appelant qui se chargera alors de les traiter à un niveau plus haut.
a++
Les ignorer ça ne fait pas un code sale, ça les laisse remonter toutes seules. Charge à l’appelant de les traiter
Je dirais au contraire que c’est les ignorer des exception qui correspondrait à un codage sale.
Ici cela permet justement de logger les exceptions sans les ignorer.
J’ai du mal à comprendre l’intérêt du rethrow. Pour moi le code suivant
public void method() throws IOException {
try {
// CODE qui peut remonter une IOException
} catch (final Exception e) {
logger.log(e);
throw e;
}
}
est un code de cochon. On ne devrait catcher que les exceptions levées par le code du bloc try… Le rethrow ressemble (pour moi) à une pirouette pour arranger ceux qui codent avec leurs pieds
Bien, j’étais vraiment déçu de voir que ce qui me semblait une évolution assez simple et bien pratique ait été écarté.
Je garde toujours la même réserve que lors de la proposition initiale sur la syntaxe du multi-catch qui ne permet pas de définir le type de l’exception à l’intérieur du catch. Je suppose donc qu’il sera systématiquement Throwable.
De plus je ne suis pas fan du | comme séparateur de classe.
J’aurais préféré une syntaxe de type :
catch (final Exception e : IOException, SQLException) { ... }
Hé bien je n’ai qu’un mot à dire « enfin » ! Il était temps que cette proposition soit revue. Reste à espérer qu’elle seras retenue pour de bon.
dommage que le rethrow ne permette pas de wrapper en runtime exception par la même occasion :$