Puis-je intercepter plusieurs exceptions Java dans la même clause catch?

699

En Java, je veux faire quelque chose comme ça:

try {
    ...     
} catch (/* code to catch IllegalArgumentException, SecurityException, 
            IllegalAccessException, and NoSuchFieldException at the same time */) {
   someCode();
}

...au lieu de:

try {
    ...     
} catch (IllegalArgumentException e) {
    someCode();
} catch (SecurityException e) {
    someCode();
} catch (IllegalAccessException e) {
    someCode();
} catch (NoSuchFieldException e) {
    someCode();
}

Y a-t-il un moyen de faire ça?

froadie
la source

Réponses:

1131

Cela est possible depuis Java 7 . La syntaxe d'un bloc à prises multiples est:

try { 
  ...
} catch (IOException | SQLException ex) { 
  ...
}

N'oubliez pas, cependant, que si toutes les exceptions appartiennent à la même hiérarchie de classes, vous pouvez simplement intercepter ce type d'exception de base.

Notez également que vous ne pouvez pas intercepter ExceptionA et ExceptionB dans le même bloc si ExceptionB est hérité, directement ou indirectement, d'ExceptionA. Le compilateur se plaindra:

Alternatives in a multi-catch statement cannot be related by subclassing
  Alternative ExceptionB is a subclass of alternative ExceptionA
OscarRyz
la source
81
TT - pourquoi redéfinir l' opérateur bitwise or( |)? Pourquoi ne pas utiliser une virgule ou l'opérateur qui a une signification plus similaire, le logical or( ||)?
ArtOfWarfare
11
@ArtOfWarfare Peut-être pensaient-ils que cela n'aurait plus d'importance après avoir déjà défini la syntaxe des bornes multiples pour les génériques.
JimmyB
12
Le signe XOR (I) n'est pas identique à OR (||), A | B signifie A ou B mais pas les deux A || B signifie A ou B ou les deux, de sorte que pour les exceptions, il s'agit de l'exception A ou de l'exception B, mais pas des deux en même temps. c'est pourquoi ils ont utilisé XOR chanter au lieu de OR et vous pouvez le voir clairement lorsque l'exception est levée si vous mettez 2 exceptions, l'une d'entre elles est un sous-type de l'autre
user1512999
41
@ user1512999 en Java, XOR au niveau du bit est ^ (caret) et OR au niveau du bit est | (pipe) docs.oracle.com/javase/tutorial/java/nutsandbolts/op3.html
Lewis Baumstark
6
Il convient de mentionner que le type d'une exception capturée dans un bloc à prises multiples est évalué pour le parent commun le plus dérivé
yanpas
104

Pas exactement avant Java 7 mais je ferais quelque chose comme ça:

Java 6 et versions antérieures

try {
  //.....
} catch (Exception exc) {
  if (exc instanceof IllegalArgumentException || exc instanceof SecurityException || 
     exc instanceof IllegalAccessException || exc instanceof NoSuchFieldException ) {

     someCode();

  } else if (exc instanceof RuntimeException) {
     throw (RuntimeException) exc;     

  } else {
    throw new RuntimeException(exc);
  }

}



Java 7

try {
  //.....
} catch ( IllegalArgumentException | SecurityException |
         IllegalAccessException |NoSuchFieldException exc) {
  someCode();
}
user454322
la source
11
Notez que votre exemple Java 6 brise la capacité du compilateur à dire ce qui sera lancé d'où.
MichaelBlume
2
@MichaelBlume True, ce qui n'est pas [si] mauvais. Vous pouvez toujours obtenir l'exception d'origine avec exc.getCause(). En parallèle, Robert C. Martin (entre autres) recommande d'utiliser des exceptions non contrôlées (le compilateur n'a aucune idée du type d'exception qui sera levé à partir de là); reportez-vous au Chapitre 7: Gestion des erreurs sur son livre Clean code .
user454322
4
Dans votre exemple Java 6, ne devez-vous pas renvoyer l'exception d'origine au lieu de créer une nouvelle instance d'exception, c'est-à-dire throw excau lieu de throw new RuntimeException(exc)?
David DeMar
5
C'est une très mauvaise pratique, du point de vue de la lisibilité.
Rajesh J Advani
3
L'instance de fonctionnement est un peu coûteuse, il vaut mieux éviter autant que possible.
Paramesh Korrakuti
23

Dans Java 7, vous pouvez définir plusieurs clauses catch comme:

catch (IllegalArgumentException | SecurityException e)
{
    ...
}
crusam
la source
16

S'il existe une hiérarchie d'exceptions, vous pouvez utiliser la classe de base pour intercepter toutes les sous-classes d'exceptions. Dans le cas dégénéré, vous pouvez intercepter toutes les exceptions Java avec:

try {
   ...
} catch (Exception e) {
   someCode();
}

Dans un cas plus courant, si RepositoryException est la classe de base et PathNotFoundException est une classe dérivée, alors:

try {
   ...
} catch (RepositoryException re) {
   someCode();
} catch (Exception e) {
   someCode();
}

Le code ci-dessus intercepte RepositoryException et PathNotFoundException pour un type de gestion des exceptions et toutes les autres exceptions sont regroupées. Depuis Java 7, selon la réponse de @ OscarRyz ci-dessus:

try { 
  ...
} catch( IOException | SQLException ex ) { 
  ...
}
Michael Shopsin
la source
7
Les clauses catch BTW sont traitées dans l'ordre, donc si vous mettez une classe d'exception parent avant une classe enfant, elle n'est jamais appelée par exemple: try {...} catch (Exception e) {someCode (); } catch (RepositoryException re) {// jamais atteint}
Michael Shopsin
4
En fait précisément parce qu'il ne peut jamais être atteint, un tel code ne se compile même pas.
polygenelubricants
15

Non, un par client.

Vous pouvez intercepter une superclasse, comme java.lang.Exception, tant que vous effectuez la même action dans tous les cas.

try {
    // some code
} catch(Exception e) { //All exceptions are caught here as all are inheriting java.lang.Exception
    e.printStackTrace();
}

Mais ce n'est peut-être pas la meilleure pratique. Vous ne devez intercepter une exception que si vous avez une stratégie pour la gérer réellement - et que la journalisation et la reprise ne sont pas des «manipulations». Si vous n'avez pas d'action corrective, mieux vaut l'ajouter à la signature de la méthode et la laisser bouillonner jusqu'à quelqu'un qui peut gérer la situation.

duffymo
la source
20
Puis-je vous demander de reformuler la partie concernant la capture de java.lang.Exception? Je me rends compte que c'est un exemple, mais j'ai l'impression que certaines personnes pourraient lire cette réponse et dire: "oh, d'accord, je vais juste attraper une exception alors", alors que ce n'est probablement pas ce qu'ils veulent (ou devraient) faire.
Rob Hruska
2
Je le savais, mais je ne veux pas le faire ... Oh, eh bien, je suppose que je suis coincé avec 4 captures alors, jusqu'à la prochaine version de Java ...
froadie
@duffymo: Qu'est-ce qui ne va pas avec la journalisation et le retour? Sauf qu'il encombre le code, son équivalent à ne pas l'attraper, n'est-ce pas. Vu du point de vue de la stratégie générale de gestion des erreurs. Ce qui est mauvais, c'est la journalisation et non le retour.
Frank Osterfeld
5
Je ne considère pas la journalisation et la reprise de la manipulation de quoi que ce soit. Je préfèrerais laisser faire des bulles à quelqu'un qui peut faire quelque chose de significatif. Cette dernière couche où les exceptions ne devraient jamais s'échapper (par exemple, les contrôleurs dans une application Web) devrait être celle qui consigne l'erreur dans ce cas.
duffymo
Suis-je le seul à trouver absurde qu'un journal ne soit pas généré automatiquement pour moi? Il semble que nous devons tous écrire le même message de consignation stupide chaque fois qu'un morceau de code peut lever une exception.
ArtOfWarfare
10

Une alternative plus propre (mais moins verbeuse, et peut-être pas aussi préférée) à la réponse de user454322 sur Java 6 (c'est-à-dire Android) serait d'attraper tous les Exceptions et de relancer les RuntimeExceptions. Cela ne fonctionnerait pas si vous envisagez d'attraper d'autres types d'exceptions plus haut dans la pile (sauf si vous les relancez également), mais interceptera efficacement toutes les exceptions vérifiées .

Par exemple:

try {
    // CODE THAT THROWS EXCEPTION
} catch (Exception e) {
    if (e instanceof RuntimeException) {
        // this exception was not expected, so re-throw it
        throw e;
    } else {
        // YOUR CODE FOR ALL CHECKED EXCEPTIONS
    } 
}

Cela étant dit, pour la verbosité, il pourrait être préférable de définir un booléen ou une autre variable et en fonction de cela, exécuter du code après le bloc try-catch.

Oleg Vaskevich
la source
1
Cette approche empêche le compilateur de déterminer si un "bloc catch" sera accessible ou non.
the_new_mr
3

En pré-7, que diriez-vous:

  Boolean   caught = true;
  Exception e;
  try {
     ...
     caught = false;
  } catch (TransformerException te) {
     e = te;
  } catch (SocketException se) {
     e = se;
  } catch (IOException ie) {
     e = ie;
  }
  if (caught) {
     someCode(); // You can reference Exception e here.
  }
Factures
la source
3
serait une bonne solution. Que diriez-vous d'insérer le contrôle final de caughtdans un finallybloc?
Andrea_86
Cela nécessite plus de lignes que la question d'origine.
Leandro Glossman
1

Oui. Voici la façon d'utiliser le séparateur de tuyaux (|),

try
{
    .......
}    
catch
{
    catch(IllegalArgumentException | SecurityException | IllegalAccessException | NoSuchFieldException e)
}
Shiva
la source
Quel est ce style de code? Le bloc catch dans un bloc try?
Sam
1

Pour kotlin, ce n'est pas possible pour l'instant mais ils ont envisagé de l'ajouter: Source
Mais pour l'instant, juste un petit truc:

try {
    // code
} catch(ex:Exception) {
    when(ex) {
        is SomeException,
        is AnotherException -> {
            // handle
        }
        else -> throw ex
    }
}
Dr.jacky
la source
0

Attrapez l'exception qui se trouve être une classe parente dans la hiérarchie des exceptions. C'est bien sûr une mauvaise pratique . Dans votre cas, l'exception parent commune se trouve être la classe Exception, et intercepter toute exception qui est une instance d'Exception est en effet une mauvaise pratique - les exceptions comme NullPointerException sont généralement des erreurs de programmation et doivent généralement être résolues en vérifiant les valeurs nulles.

Vineet Reynolds
la source