Renvoyer les exceptions en Java sans perdre la trace de la pile

417

En C #, je peux utiliser l' throw;instruction pour renvoyer une exception tout en préservant la trace de la pile:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

Y a-t-il quelque chose comme ça en Java ( qui ne perd pas la trace de pile d'origine )?

ripper234
la source
4
Pourquoi pensez-vous qu'il perd la trace de pile d'origine? La seule façon de le perdre lorsque vous lancez une nouvelle SomeOtherException et oubliez d'affecter la cause racine dans le constructeur ou dans initCause ().
akarnokd
4
Je crois que c'est ainsi que se comporte le code dans .Net, mais je ne suis plus positif. Il peut être utile de le rechercher quelque part ou d'exécuter un petit test.
ripper234
11
Throwables ne sont pas modifiés en les jetant. Pour mettre à jour la trace de pile, vous devez appeler fillInStackTrace(). Idéalement, cette méthode est appelée dans le constructeur de a Throwable.
Robert
50
En C #, oui, throw e;perdra la trace de pile. Mais pas en Java.
Tim Goodman

Réponses:

561
catch (WhateverException e) {
    throw e;
}

renverra simplement l'exception que vous avez interceptée (la méthode environnante doit évidemment le permettre via sa signature, etc.). L'exception conservera la trace de pile d'origine.

Brian Agnew
la source
4
Salut, InterruptedException e donne un message d'exception non géré lorsque j'ajoute la ligne throw e. Ce n'est pas le cas si je le remplace par l'exception plus large e. Comment cela doit-il être fait correctement?
James P.
1
@James, je viens d'observer que le message disparaît si vous ajoutez "throws XxxException" dans la déclaration de fonction.
shiouming
2
Dans Java 7, le compilateur pour une telle relance est plus intelligent. Maintenant, cela fonctionne très bien avec des exceptions spécifiques "jette" dans la méthode contenant.
Waldemar Wosiński
193
@James Si vous catch(Exception e) { throw e; }cela ne sera pas géré. Si vous, catch(InterruptedException ie) { throw ie; }il sera traité. En règle générale, ne le faites pas catch(Exception e)- ce n'est pas un pokemon, et nous ne voulons pas tous les attraper!
corsiKa
3
@corsiKa Ce n'est pas nécessairement vrai que vous ne voulez pas "les attraper tous", c'est juste un cas d'utilisation différent. Si vous avez une boucle de niveau supérieur ou un gestionnaire d'événements (par exemple, à l'intérieur de l'exécution d'un thread) si vous n'attrapez pas au moins RuntimeException et ne l'enregistrez pas, vous passerez souvent à côté de l'exception ET briserez silencieusement une boucle importante pour quoi est souvent un échec unique. C'est aussi très bon pour la fonctionnalité de plugin où vous ne savez pas ce que du code supplémentaire pourrait faire ou lancer ... Pour des utilisations descendantes comme celles-ci, la capture d'exception est souvent non seulement une bonne idée mais une meilleure pratique.
Bill K
82

Je préférerais:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}
Markus Lausberg
la source
6
Certainement approprié en Java pour intercepter des exceptions spécifiques que génériques et en vérifiant par exemple. +1
amischiefr
8
-1 parce que vous ne devez jamais attraper une "exception" simple à moins de savoir ce que vous faites.
Stroboskop
19
@Stroboskop: vrai, mais pour répondre, il vaut mieux utiliser le même code (similaire) que dans la question!
user85421
14
Parfois, attraper toutes les exceptions est correct. Comme lorsque vous écrivez un scénario de test. Ou à des fins de journalisation. Ou dans le principal où ne pas attraper signifie s'écraser.
John Henckel,
1
@JohnHenckel et autres: points valides entrés. J'ai mis à jour la question pour préciser que la capture Exceptionn'est généralement pas la bonne chose à faire, dans la plupart (mais pas tous) les cas.
Per Lundberg
74

Vous pouvez également envelopper l'exception dans une autre ET conserver la trace de pile d'origine en passant l'exception comme Throwable comme paramètre de cause:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}
Olvagor
la source
8
Je conseillerais également d'ajouter un message à côté, en utilisantthrow new YourOwnException("Error while trying to ....", e);
Julien
c'est ce que je cherchais, en particulier la version du premier commentaire où vous pouvez passer votre propre message
Csaba
Cela affiche le message d'erreur correctement mais la trace de la pile affiche la ligne d'erreur en tant que ligne avec 'throw new ....... (e)' et non la ligne d'origine qui a provoqué l'exception.
Ashburn RK
22

En Java, c'est presque la même chose:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}
alves
la source
5
Non, tant que vous n'instanciez pas un nouvel objet Exception, la trace de pile reste la même.
Mnementh
28
J'ajouterais une capture spécifique pour FooException
dfa
3
Dans ce cas spécifique, je suis d'accord, mais l'ajout d'une capture spécifique peut ne pas être le bon choix - imaginez que vous avez un code commun pour toutes les exceptions et après, pour une exception particulière, le relancez.
alves
1
@MarkusLausberg Mais finalement, il n'y a pas d'exceptions.
Robert
Oui, mais ce n'était pas la question.
Markus Lausberg
14

En Java, vous lancez simplement l'exception que vous avez interceptée, throw eplutôt que juste throw. Java conserve la trace de la pile.

David M
la source
6

quelque chose comme ça

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}
cdeszaq
la source
5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Ceci est un exemple concret où la méthode lance un IOException. Le finalmoyen tne peut contenir qu'une exception levée depuis le bloc try. Des documents de lecture supplémentaires peuvent être trouvés ici et ici .

Daniel
la source
1
Cela ne doit pas être définitif. Voir docs.oracle.com/javase/7/docs/technotes/guides/language/… et stackoverflow.com/a/6889301/131160
jcsahnwaldt indique GoFundMonica
3

La trace de pile est conservée si vous encapsulez l'excétion capturée dans une autre exception (pour fournir plus d'informations) ou si vous relancez simplement l'excision capturée.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }

Sindre
la source
2

Je venais juste d'avoir une situation similaire dans laquelle mon code lève potentiellement un certain nombre d'exceptions différentes que je voulais simplement renverser. La solution décrite ci-dessus ne fonctionnait pas pour moi, car Eclipse m'a dit que cela throw e;conduisait à une exception non gérée, alors je viens de faire ceci:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

A travaillé pour moi .... :)

Matthias
la source