Course Content
Java JUnit Library. Types of Testing
Java JUnit Library. Types of Testing
Handling Multiple Exceptions
As mentioned in the previous chapter, we can have multiple exceptions, and for each of such exceptions, we can have a separate catch block.
Multiple `catch` blocks
Let's take a look at a code example that parses a String
into an int
and then performs division. In this case, there can be two exceptions:
ArithmeticException
if we attempt division by zero;NumberFormatException
if it's impossible to convert theString
into anint
.
The method is very simple but throws enough exceptions.
Let's use this method in the main class and handle both exceptions using a try-catch
structure:
main
package com.example; public class Main { public static void main(String[] args) { try { // Call the method that might throw multiple exceptions String input = "10"; int divisor = 0; double result = divideAndConvert(input, divisor); System.out.println("Result: " + result); } catch (ArithmeticException e) { System.out.println("ArithmeticException caught"); } catch (NumberFormatException e) { System.out.println("NumberFormatException caught"); } } public static double divideAndConvert(String numberStr, int divisor) { int number = Integer.parseInt(numberStr); // Can throw NumberFormatException if (divisor == 0) { throw new ArithmeticException("You can't divide by zero!"); } return (double) number / divisor; // Can throw ArithmeticException } }
As you can see, we handle multiple exceptions, one after the other, using two catch
blocks. If we catch the first exception, in our case, ArithmeticException
, we enter the first catch block and display the necessary information on the screen.
If we catch the second error, which is NumberFormatException
in this case, we enter the next catch block, where we display the required information on the screen.
We also give each of the errors an alias, 'e
', which allows us to access the object and understand what went wrong.
This is done using e.getMessage()
. In code, it will look like this:
main
package com.example; public class Main { public static void main(String[] args) { try { // Call the method that might throw multiple exceptions String input = "10"; int divisor = 0; double result = divideAndConvert(input, divisor); System.out.println("Result: " + result); } catch (ArithmeticException e) { System.out.println("ArithmeticException caught: " + e.getMessage()); } catch (NumberFormatException e) { System.out.println("NumberFormatException caught: " + e.getMessage()); } } public static double divideAndConvert(String numberStr, int divisor) { int number = Integer.parseInt(numberStr); // Can throw NumberFormatException if (divisor == 0) { throw new ArithmeticException("You can't divide by zero!"); } return (double) number / divisor; // Can throw ArithmeticException } }
Combining multiple `catch` blocks
You may notice that we perform the same operation in both catch
blocks, which hints at the idea that we could combine them. Java allows us to do that by catching both exception objects in a single catch
block.
For example:
main
package com.example; public class Main { public static void main(String[] args) { try { // Call the method that might throw multiple exceptions String input = "10d"; int divisor = 2; double result = divideAndConvert(input, divisor); System.out.println("Result: " + result); } catch (ArithmeticException | NumberFormatException e) { System.out.println(e.getClass().getSimpleName() + " caught: " + e.getMessage()); } } public static double divideAndConvert(String numberStr, int divisor) { int number = Integer.parseInt(numberStr); // Can throw NumberFormatException if (divisor == 0) { throw new ArithmeticException("You can't divide by zero!"); } return (double) number / divisor; // Can throw ArithmeticException } }
We've listed multiple possible exceptions that we can catch using the bitwise OR (|
). This way, in one catch
block, we catch two possible exceptions simultaneously and display a common message for them.
We can slightly shorten this catch
block by using the parent exception class object: RuntimeException
.
Let's implement this in the code below:
main
package com.example; public class Main { public static void main(String[] args) { try { // Call the method that might throw multiple exceptions String input = "10"; int divisor = 0; double result = divideAndConvert(input, divisor); System.out.println("Result: " + result); } catch (RuntimeException e) { System.out.println(e.getClass().getSimpleName() + " caught: " + e.getMessage()); } } public static double divideAndConvert(String numberStr, int divisor) { int number = Integer.parseInt(numberStr); // Can throw NumberFormatException if (divisor == 0) { throw new ArithmeticException("You can't divide by zero!"); } return (double) number / divisor; // Can throw ArithmeticException } }
We can conclude that exceptions also have their own inheritance hierarchy, and we can substitute a child class for a parent class, as well as use dependency inversion.
Thanks for your feedback!