Catching Multiple Exception Types in One Catch Block

Catching multiple exception types in one catch block

Update:

As of PHP 7.1, this is available.

The syntax is:

try
{
// Some code...
}
catch(AError | BError $e)
{
// Handle exceptions
}
catch(Exception $e)
{
// Handle the general case
}

Docs: https://www.php.net/manual/en/language.exceptions.php#example-294

RFC: https://wiki.php.net/rfc/multiple-catch

Commit: https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a



For PHP before 7.1:

Despite what these other answers say, you can catch AError and BError in the same block (it is somewhat easier if you are the one defining the exceptions). Even given that there are exceptions you want to "fall through", you should still be able to define a hierarchy to match your needs.

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

Then:

catch(LetterError $e){
//voodoo
}

As you can see here and here, even the SPL default exceptions have a hierarchy you can leverage. Additionally, as stated in the PHP Manual:

When an exception is thrown, code following the statement will not be
executed, and PHP will attempt to find the first matching catch block.

This means you could also have

class CError extends LetterError {}

which you need to handle differently than AError or BError, so your catch statement would look like this:

catch(CError $e){
//voodoo
}
catch(LetterError $e){
//voodoo
}

If you had the case where there were twenty or more exceptions that legitimately belonged under the same superclass, and you needed to handle five (or whatever large-ish group) of them one way and the rest the other, you can STILL do this.

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

And then:

catch (Group1 $e) {}

Using OOP when it comes to exceptions is very powerful. Using things like get_class or instanceof are hacks, and should be avoided if possible.

Another solution I would like to add is putting the exception handling functionality in its own method.

You could have

function handleExceptionMethod1(Exception $e)
{
//voodoo
}

function handleExceptionMethod2(Exception $e)
{
//voodoo
}

Assuming there is absolutely no way you can control exception class hierarchies or interfaces (and there almost always will be a way), you can do the following:

try
{
stuff()
}
catch(ExceptionA $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
$this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
$this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
$this->handleExceptionMethod2($e);
}

In this way, you are still have a only single code location you have to modify if your exception handling mechanism needs to change, and you are working within the general constructs of OOP.

Can I catch multiple Java exceptions in the same catch clause?

This has been possible since Java 7. The syntax for a multi-catch block is:

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

Remember, though, that if all the exceptions belong to the same class hierarchy, you can simply catch that base exception type.

Also note that you cannot catch both ExceptionA and ExceptionB in the same block if ExceptionB is inherited, either directly or indirectly, from ExceptionA. The compiler will complain:

Alternatives in a multi-catch statement cannot be related by subclassing
Alternative ExceptionB is a subclass of alternative ExceptionA

The fix for this is to only include the ancestor exception in the exception list, as it will also catch exceptions of the descendant type.

Is it possible to catch multiple exceptions and perform different logic upon them without using multiple catch statements?

That doesn't make sense. When you use a multi catch, then you are implicitly saying: all of "these" exceptions should fall into the same bucket.

Of course, you can then do some instanceof if/else trees, but heck: the java way of doing that would be to have different catch statements for each one.

But, also of course, depending on context, it might be pragmatic to do something like

 catch(XException | YException | ZException  xyOrZ) {
log(xyOrZ);
handle(xyOrZ);

where handle() does some instanceof "switching".

Long story short: multi catch is a convenient way to enable an aspect (such as logging) that works for all exceptions. But it can get into your way regarding exception specific handling. You simply have to balance your requirements, and use that solution that your team finds to best fit your needs. To a certain degree, this is about style, and style questions are decided by the people working the code base.

Catch multiple exceptions at once?

Catch System.Exception and switch on the types

catch (Exception ex)            
{
if (ex is FormatException || ex is OverflowException)
{
WebId = Guid.Empty;
return;
}

throw;
}

Specific and same actions when catching multiple exceptions

Use the catch (ExceptionA | ExceptionB e) construct. Within the catch block, first do an instanceof check for e and handle the exception types separately. After this, have the common handling for both types. This way you can do everything in one catch block:

try {
// do something...
} catch (ExceptionA | ExceptionB e) {
if (e instanceof ExceptionA) {
// handling for ExceptionA
} else {
// handling for ExceptionB
}
// common handling for both exception types
}

Catching multiple exceptions in Java-8

The type of the expression

b ? new Excep1() : new Excep2()

is Exception, since that's the common supertype of Excep1 and Excep2.

However, you are not catching Exception, so the compiler complains about it.

If you catch Exception, it will pass compilation:

public int m2(boolean b) {
try {
throw b ? new Excep1() : new Excep2();
} catch (Exception e) {
return 0;
}
}

I tried to find the JLS entry that explains the type of conditional ternary expression in your example.

All I could find was that this particular expression is a 15.25.3. Reference Conditional Expression.

I'm not entirely sure if it counts as a poly expression or a standalone expression. I think it's standalone (since poly expressions involve an assignment context or an invocation context, and I don't think a throw statement counts as either of those).

For a standalone expression: "If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression."

In your case, the second and third operands have three common types - Object, Throwable and Exception - the type of the expression must be one of the latter two, since, "The Expression in a throw statement must either denote a variable or value of a reference type which is assignable (§5.2) to the type Throwable."

It appears that the compiler picks the most specific common type (Exception), and therefore a catch (Exception e) solves the compilation error.

I also tried to replace your two custom exceptions with two sub-classes of IOException, in which case catch (IOException e) solves the compilation error.

Catch multiple exceptions in one line (except block)

From Python Documentation:

An except clause may name multiple exceptions as a parenthesized tuple, for example

except (IDontLikeYouException, YouAreBeingMeanException) as e:
pass

Or, for Python 2 only:

except (IDontLikeYouException, YouAreBeingMeanException), e:
pass

Separating the exception from the variable with a comma will still work in Python 2.6 and 2.7, but is now deprecated and does not work in Python 3; now you should be using as.

Is it possible in Java to catch two exceptions in the same catch block?

Java 7 and later

Multiple-exception catches are supported, starting in Java 7.

The syntax is:

try {
// stuff
} catch (Exception1 | Exception2 ex) {
// Handle both exceptions
}

The static type of ex is the most specialized common supertype of the exceptions listed. There is a nice feature where if you rethrow ex in the catch, the compiler knows that only one of the listed exceptions can be thrown.



Java 6 and earlier

Prior to Java 7, there are ways to handle this problem, but they tend to be inelegant, and to have limitations.

Approach #1


try {
// stuff
} catch (Exception1 ex) {
handleException(ex);
} catch (Exception2 ex) {
handleException(ex);
}

public void handleException(SuperException ex) {
// handle exception here
}

This gets messy if the exception handler needs to access local variables declared before the try. And if the handler method needs to rethrow the exception (and it is checked) then you run into serious problems with the signature. Specifically, handleException has to be declared as throwing SuperException ... which potentially means you have to change the signature of the enclosing method, and so on.

Approach #2


try {
// stuff
} catch (SuperException ex) {
if (ex instanceof Exception1 || ex instanceof Exception2) {
// handle exception
} else {
throw ex;
}
}

Once again, we have a potential problem with signatures.

Approach #3


try {
// stuff
} catch (SuperException ex) {
if (ex instanceof Exception1 || ex instanceof Exception2) {
// handle exception
}
}

If you leave out the else part (e.g. because there are no other subtypes of SuperException at the moment) the code becomes more fragile. If the exception hierarchy is reorganized, this handler without an else may end up silently eating exceptions!



Related Topics



Leave a reply



Submit