Catching Exceptions with "Catch, When"

Catching exceptions with catch, when

Catch blocks already allow you to filter on the type of the exception:

catch (SomeSpecificExceptionType e) {...}

The when clause allows you to extend this filter to generic expressions.

Thus, you use the when clause for cases where the type of the exception is not distinct enough to determine whether the exception should be handled here or not.


A common use case are exception types which are actually a wrapper for multiple, different kinds of errors.

Here's a case that I've actually used (in VB, which already has this feature for quite some time):

try
{
SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
// Handle the *specific* error I was expecting.
}

Same for SqlException, which also has an ErrorCode property. The alternative would be something like that:

try
{
SomeLegacyComOperation();
}
catch (COMException e)
{
if (e.ErrorCode == 0x1234)
{
// Handle error
}
else
{
throw;
}
}

which is arguably less elegant and slightly breaks the stack trace.

In addition, you can mention the same type of exception twice in the same try-catch-block:

try
{
SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
...
}
catch (COMException e) when (e.ErrorCode == 0x5678)
{
...
}

which would not be possible without the when condition.

Catching exceptions with try-catch

Exceptions should only be caught only if you can do something to fix
that exceptional situation

fixing maybe not the best word here. You should catch exception if you can handle it. Handling may mean:

  • fixing problem or returning some default values
  • retrying something
  • logging or notifying user (I believe every exception should be logged, even if you can fix it)
  • throwing more high-level exception

But you should not catch exceptions and do nothing:

catch(FormatException ex)
{
}

That just swallows exception and you will never know if something bad happened.

Throwing and Catching Exceptions

You generally catch an exception in a method when you want your program to continue running. You throw an exception when you want a higher level method that is calling that method to handle the exception instead. For example, you might throw it all the way back to your Main method, which has a try..catch block (likely with different catch blocks for different exceptions) encapsulating all your method calls, and exceptions can be handled there (for example by ending the program).

Remember that throwing an exception will end the method immediately. This affects the flow of your code. If you might have an exception in the middle of the method, and the code below it can't run if that exception happened, then you would need to either wrap the whole section in a try/catch block or throw an exception.

A general word of advice - printStackTrace() is bad. You can create better error output yourself (and you can include the stack trace as well with your output). Even better, use logging.

I recommend reading this introduction to exceptions and this article which covers good and bad exception patterns.

Throwing exceptions as well as catching exceptions?

The catch block has greater priority over the method level throw declarations. If something would pass by that catch block, it would be thrown by the method (but that's not the case since all your mentioned exceptions are indeed inheriting from the Exception).

If you need an exception to be handled by the catch block but forwarded further, you would have to rethrow it, e.g.

throw e;

Order of catching exceptions in Java

The order is whatever matches first, gets executed (as the JLS clearly explains).

If the first catch matches the exception, it executes, if it doesn't, the next one is tried and on and on until one is matched or none are.

So, when catching exceptions you want to always catch the most specific first and then the most generic (as RuntimeException or Exception). For instance, imagine you would like to catch the StringIndexOutOfBoundsException thrown by the String.charAt(index) method but your code could also throw a NullPointerException, here's how you could go to catch the exceptions:

String s = null;
try {
s.charAt(10);
} catch ( NullPointerExeption e ) {
System.out.println("null");
e.printStackTrace();
} catch ( StringIndexOutOfBoundsException e ) {
System.out.println("String index error!");
e.printStackTrace();
} catch ( RuntimeException e ) {
System.out.println("runtime exception!");
e.printStackTrace();
}

So, with this order, I am making sure the exceptions are caught correctly and they are not tripping over one another, if it's a NullPointerException it enters the first catch, if a StringIndexOutOfBoundsException it enters the second and finally if it is something else that is a RuntimeException (or inherits from it, like a IllegalArgumentException) it enters the third catch.

Your case is correct as IOException inherits from Exception and RuntimeException also inherits from Exception, so they will not trip over one another.

It's also a compilation error to catch a generic exception first and then one of it's descendants later, as in:

try {
// some code here
} catch ( Exception e) {
e.printStackTrace();
} catch ( RuntimeException e ) { // this line will cause a compilation error because it would never be executed since the first catch would pick the exception
e.printStackTrace();
}

So, you should have the children first and then the parent exceptions.



Related Topics



Leave a reply



Submit