Until now, we have used try/catch
blocks with at most one catch
block to capture the exceptions thrown in the try
block. But, in Java it is possible to use more than one catch
block for a single try
block. This allows us to catch and handle exceptions of more than one type (including all of its subclasses), and handle each in a different way.
Order of the catch
blocks
When using multiple catch
blocks, if an exception is thrown, the blocks are considered in the same order as they appear in the code. So if one exception matches the type of more than one catch
block (remember that each catch
block also catches all of the subclasses of the specified exception type), only the topmost block is executed.
For example, the following program considers the possible exceptions that might occur when dividing two elements of an ArrayList
:
List<Integer> list = new ArrayList<>();
list.add(36);
list.add(4);
list.add(0);
try {
int result = list.get(0) / list.get(1); // 36/4
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException e) {
System.out.println("An IndexOutOfBoundsException occurred: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred: " + e.getMessage());
} catch (Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
The result is: 9
But, if we select an index that doesn’t exist in the ArrayList
:
List<Integer> list = new ArrayList<>();
list.add(36);
list.add(4);
list.add(0);
try {
int result = list.get(0) / list.get(5); // Index 5 is out of bounds
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException e) {
System.out.println("An IndexOutOfBoundsException occurred: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred: " + e.getMessage());
} catch (Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
An IndexOutOfBoundsException occurred: Index: 5, Size: 3
An exception is captured by the first catch
block.
Moreover, if we select 0
(the 3rd element in the list) as the divisor:
List<Integer> list = new ArrayList<>();
list.add(36);
list.add(4);
list.add(0);
try {
int result = list.get(0) / list.get(2); // 36/0
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException e) {
System.out.println("An IndexOutOfBoundsException occurred: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred: " + e.getMessage());
} catch (Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
An ArithmeticException occurred: / by zero
Now, the exception is captured by the second catch
block.
In the case that an exception is thrown, but it isn’t of type IndexOutOfBoundsException
or ArithmeticException
, it will be captured by the last catch
block, as Exception
is a superclass for all exceptions. For example, if the ArrayList
is null
, a NullPointerException
will be thrown:
List<Integer> list = null;
try {
int result = list.get(0) / list.get(1); // list is null
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException e) {
System.out.println("An IndexOutOfBoundsException occurred: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println("An ArithmeticException occurred: " + e.getMessage());
} catch (Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
Some other exception occurred: class java.lang.NullPointerException
In this way we can capture all exceptions while handling some in a specific way. It is important that you place the catch
for the most specific exceptions first, to avoid a superclass capturing more exceptions than it should.
In our previous example, if we place the catch( Exception e )
block first, it will capture all exceptions thrown in the try
block, as all of them are subclasses of Exception
. If this happens, our other catch
blocks will never be invoked, as they will never capture any exceptions.
Multiple exception types in a single catch
block
Starting from Java 7, it is possible to catch more than one type of exception with the same catch
block. This is done by placing all of the exception types in the argument for catch
, separated by a pipe symbol, |
. For example, if we wanted to have just one exception handler in the previous example for the IndexOutOfBoundsException
and ArithmeticException
types, we can do it in the following way:
List<Integer> list = new ArrayList<>();
list.add(36);
list.add(4);
list.add(0);
try {
int result = list.get(0) / list.get(5); // Index 5 is out of bounds
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException | ArithmeticException e) {
System.out.println("An IndexOutOfBoundsException or ArithmeticException occurred: " + e.getMessage());
} catch(Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
An IndexOutOfBoundsException or ArithmeticException occurred: Index: 5, Size: 3
In this case, an IndexOutOfBoundsException
was thrown and it was captured by the first catch
block. Now let’s see what happens when we divide by 0
and an ArithmeticException
is thrown:
List<Integer> list = new ArrayList<>();
list.add(36);
list.add(4);
list.add(0);
try {
int result = list.get(0) / list.get(2); // 36/0
System.out.println("The result is: " + result);
} catch(IndexOutOfBoundsException | ArithmeticException e) {
System.out.println("An IndexOutOfBoundsException or ArithmeticException occurred: " + e.getMessage());
} catch(Exception e) {
System.out.println("Some other exception occurred: " + e.getClass());
}
Output:
An IndexOutOfBoundsException or ArithmeticException occurred: / by zero
As expected, the exception was again captured by the same catch
block.
A single catch block can capture more than two types of exceptions. For example by using: catch( IndexOutOfBoundsException | ArithmeticException | IllegalArgumentException | NullPointerException e) .
|