web-dev-qa-db-fra.com

Pourquoi attraper Exception n'attrape-t-il pas RuntimeException?

C'est très étrange pour moi. RuntimeException hérite de Exception, qui hérite de Throwable.

catch(Exception exc) { /* won't catch RuntimeException */

mais

catch(Throwable exc) { /* will catch RuntimeException */

Je sais que RuntimeException a la particularité de ne pas être coché. Mais, à ma connaissance, cela ne concerne que la question de savoir si des exceptions doivent être déclarées et non si elles sont interceptées. Et même alors, je ne sais pas pourquoi cette logique se briserait en attrapant Throwable.

Cela me concerne beaucoup car je suis dans une situation où des exceptions RuntimeExceptions peuvent être lancées dans une opération de terminal. Je ne suis pas sûr du nom de ce modèle, mais quelque chose comme ma classe EmailRoller prend un tableau de Callbacks. Le code ressemble à ceci:

for(Callback cb : callbacks) {
    try {
        cb.call(item);
    }
    catch(Exception exc) {
        logger.error("Error in callback: ", exc);
   }
}

C’est donc un cas où quelque chose comme un OOME doit survoler, car si l’un de ces rappels consomme toute la mémoire de la machine, il est certain que cela va affecter le bon fonctionnement des autres. Mais un NullPointerException? Ou un IndexOutOfBoundsException? Ceux-ci affecteront le rappel mais n'empêcheront pas les autres de s'exécuter.

En outre, ceci est un peu une conception d'entreprise. Différents programmeurs ou équipes peuvent ajouter des rappels pour traiter l'élément, mais ils doivent être isolés les uns des autres. Cela signifie qu'en tant que programmeur chargé d'isoler ces rappels, je ne devrais pas compter sur eux pour m'assurer que les erreurs ne passent pas. Capturer Exception devrait être sur la bonne ligne, mais ce n’est pas parce que RuntimeException glisse. Donc, ma question plus générale est: quel est le bon modèle ici? Juste catch(Exception | RuntimeException exc), qui, selon moi, est une erreur de syntaxe à cause de l'héritage?

41
djechlin

La prémisse de la question est erronée, car attraper Exceptionne attraper RuntimeException. Code de démonstration:

public class Test {
    public static void main(String[] args) {
        try {
            throw new RuntimeException("Bang");
        } catch (Exception e) {
            System.out.println("I caught: " + e);
        }
    }
}

Sortie:

I caught: Java.lang.RuntimeException: Bang

Votre boucle aura des problèmes si:

  • callbacks est null
  • tout ce qui modifie callbacks pendant l'exécution de la boucle (s'il s'agissait d'une collection plutôt que d'un tableau)

C'est peut-être ce que vous voyez?

116
Jon Skeet
catch (Exception ex) { ... }

VA attraper RuntimeException.

Tout ce que vous mettez en bloc sera attrapé ainsi que ses sous-classes.

23
Jan Zyka

Attraper Exception attrapera un RuntimeException

8
cmd

J'ai fait face à un scénario similaire. C'était parce que l'initialisation de classA dépendait de l'initialisation de classB. Lorsque le bloc statique de classB faisait face à une exception d'exécution, classB n'était pas initialisé. Pour cette raison, classB n'a pas généré d'exception et l'initialisation de classA a également échoué.

class A{//this class will never be initialized because class B won't intialize
  static{
    try{
      classB.someStaticMethod();
    }catch(Exception e){
      sysout("This comment will never be printed");
    }
 }
}

class B{//this class will never be initialized
 static{
    int i = 1/0;//throw run time exception 
 }

 public static void someStaticMethod(){}
}

Et oui ... intercepter Exception interceptera également les exceptions d'exécution.

3
rajya vardhan