Java try, catch, finally and Multi-catch with Examples
Introduction
When an exception is thrown, a program does not have to crash - it can catch the exception and decide what to do. Java's tools for this are the
(Note - This tutorial builds on Checked vs Unchecked ExceptionsClick to read tutorial: Checked vs Unchecked Exceptions in Java.) The try-catch block Syntax of try-catch
Where,
OUTPUT of the above code
For
Multiple catch blocks - and why order matters
A
OUTPUT of the above code
Explanation of the code
OUTPUT on compiling the above code
Multi-catch - one block for several types
When several exception types need exactly the same handling, Java 7 and later let one
OUTPUT of the above code
Two rules apply to multi-catch: the types listed cannot be subclasses of each other (
finally - code that always runs
A
OUTPUT of the above code
Explanation of the code
OUTPUT of the above code
The
try, catch and finally blocks. This tutorial explains try, catch, finally and multi-catch in Java with examples. We will start with the basic try-catch block, and follow exactly how control flows through it. We will then catch several exception types with multiple catch blocks, and see why their order matters. Next we will use multi-catch to handle several types in one block. We will then make sure clean-up code always runs with finally, including its surprises with return. Lastly, we will look at what to do inside a catch block.(Note - This tutorial builds on Checked vs Unchecked ExceptionsClick to read tutorial: Checked vs Unchecked Exceptions in Java.) The try-catch block Syntax of try-catch
Syntax of try-catch
try {
// code that might throw an exception
} catch (ExceptionType variableName) {
// code that handles the exception
}
- the statements in the
tryblock run normally. If one of them throws an exception ofExceptionType(or a subclass of it), the rest of thetryblock is skipped, and thecatchblock runs. - the exception object is available inside the
catchblock throughvariableName- usually callede. - after the
catchblock, the program carries on with the statement after the wholetry-catch. If no exception is thrown, thecatchblock is skipped.
Control flow through try-catch
//TryCatchFlow.java
public class TryCatchFlow {
static void convert(String text) {
System.out.println("Converting \"" + text + "\"");
try {
int value = Integer.parseInt(text);
System.out.println(" parsed: " + value);
System.out.println(" doubled: " + value * 2);
} catch (NumberFormatException e) {
System.out.println(" not a number: " + e.getMessage());
}
System.out.println(" done with \"" + text + "\"");
}
public static void main(String[] args) {
convert("21");
convert("twenty-one");
}
}
Converting "21" parsed: 21 doubled: 42 done with "21" Converting "twenty-one" not a number: For input string: "twenty-one" done with "twenty-one"
"twenty-one", parseInt() threw, so the two printing lines after it in the try block never ran. The catch block handled the exception, and the method carried on normally - the program did not crash.
try block can be followed by several catch blocks, one for each kind of exception that needs different handling. Java checks them from top to bottom, and runs only the first one whose type matches - a catch block for a class also catches all of its subclasses.
Several catch blocks for different exceptions
//MultipleCatch.java
public class MultipleCatch {
static void average(String[] values, String countText) {
try {
int count = Integer.parseInt(countText);
int sum = 0;
for (int i = 0; i < count; i++) {
sum += Integer.parseInt(values[i]);
}
System.out.println(" average = " + sum / count);
} catch (NumberFormatException e) {
System.out.println(" bad number: " + e.getMessage());
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println(" not enough values: " + e.getMessage());
} catch (ArithmeticException e) {
System.out.println(" cannot average zero values");
} catch (RuntimeException e) {
System.out.println(" something else went wrong: " + e);
}
}
public static void main(String[] args) {
String[] values = {"10", "20", "30"};
average(values, "3");
average(values, "x");
average(values, "5");
average(values, "0");
average(null, "2");
}
}
average = 20 bad number: For input string: "x" not enough values: Index 3 out of bounds for length 3 cannot average zero values something else went wrong: java.lang.NullPointerException: Cannot load from object array because "values" is null
- Each call failed in a different way, and the matching
catchblock handled it. Passingnullcaused aNullPointerException, which no specific block names, so the generalRuntimeExceptionblock caught it. - Specific types must come before general ones. If the
RuntimeExceptionblock came first, it would catch everything, and the blocks after it could never run - so the compiler rejects that order, as shown below.
A general catch block before a specific one
//WrongOrder.java
public class WrongOrder {
public static void main(String[] args) {
try {
Integer.parseInt("x");
} catch (RuntimeException e) {
System.out.println("general");
} catch (NumberFormatException e) {
System.out.println("specific");
}
}
}
WrongOrder.java:8: error: exception NumberFormatException has already been caught
} catch (NumberFormatException e) {
^
1 error
catch block list them, separated by |. This removes duplicate code. (The feature was introduced in Catching Multiple Exception Types in a Single Catch Block in Java 7Click to read tutorial on Java 7 multi-catch.)
Handling several exception types in one catch block
//MultiCatch.java
public class MultiCatch {
static int parseAt(String[] values, int index) {
try {
return Integer.parseInt(values[index]);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
System.out.println(" using 0 because of " + e.getClass().getSimpleName());
return 0;
}
}
public static void main(String[] args) {
String[] values = {"7", "seven"};
System.out.println("index 0 -> " + parseAt(values, 0));
System.out.println("index 1 -> " + parseAt(values, 1));
System.out.println("index 5 -> " + parseAt(values, 5));
}
}
index 0 -> 7 using 0 because of NumberFormatException index 1 -> 0 using 0 because of ArrayIndexOutOfBoundsException index 5 -> 0
IOException | FileNotFoundException is a compile error, because the first already covers the second), and the exception variable is implicitly final, so it cannot be reassigned.
finally block, placed after the catch blocks, runs whether or not an exception was thrown - and even if the try or catch block returns, or throws an exception that is not caught. It is the place for clean-up: closing files and connections, releasing locks, stopping timers. A try block can also be followed by finally alone, with no catch.
finally runs in every case
//FinallyDemo.java
public class FinallyDemo {
static String process(String input) {
System.out.println("Processing \"" + input + "\"");
try {
if (input.isEmpty()) {
return " empty input - returned early";
}
int n = Integer.parseInt(input);
return " result " + (100 / n);
} catch (NumberFormatException e) {
return " invalid number";
} finally {
System.out.println(" finally: releasing resources");
}
}
public static void main(String[] args) {
System.out.println(process("4"));
System.out.println(process(""));
System.out.println(process("abc"));
try {
System.out.println(process("0"));
} catch (ArithmeticException e) {
System.out.println(" caught in main: " + e.getMessage());
}
}
}
Processing "4" finally: releasing resources result 25 Processing "" finally: releasing resources empty input - returned early Processing "abc" finally: releasing resources invalid number Processing "0" finally: releasing resources caught in main: / by zero
- The
finallyblock ran in all four cases - a normal return, an early return, a caught exception, and anArithmeticException(division by zero) which this method did not catch. - In each case,
finallyran before the method actually returned or the exception left the method - which is why its message is printed before the result. - The only ways to skip
finallyare extreme ones, such asSystem.exit()or the JVM crashing.
finally block by hand.
The finally and return trap
Never return (or throw) from a finally block. A return in finally replaces the value returned by the try block - and silently swallows any exception that was being thrown.
return in finally overrides results and hides exceptions
//FinallyReturnTrap.java
public class FinallyReturnTrap {
@SuppressWarnings("finally")
static int overridesResult() {
try {
return 1;
} finally {
return 2;
}
}
@SuppressWarnings("finally")
static int hidesException() {
try {
throw new IllegalStateException("important failure");
} finally {
return -1;
}
}
public static void main(String[] args) {
System.out.println("overridesResult() = " + overridesResult());
System.out.println("hidesException() = " + hidesException() + " - the exception disappeared!");
}
}
overridesResult() = 2 hidesException() = -1 - the exception disappeared!
IllegalStateException vanished without a trace - the hardest kind of bug to find. (The compiler warns about this; @SuppressWarnings silences the warning only for this demonstration.)
What to do in a catch block
- Recover - use a default value, retry, or ask the user again, as the examples above do.
- Report - log the exception with its stack trace.
e.getMessage()gives the message,e.toString()the type and message, ande.printStackTrace()the full trace. - Rethrow or wrap - if this code cannot handle the problem, let it pass to the caller, or wrap it in a more meaningful exception with throwClick to read tutorial: throw vs throws in Java with Examples.
- Never leave it empty - an empty
catchblock hides problems completely. See exception handling best practicesClick to read tutorial: Java Exception Handling Best Practices.
try-catch, and followed how control skips the rest of the try block when an exception is thrown, then carries on after the catch. We then used several catch blocks, and saw that specific types must come before general ones. Next we combined types with multi-catch. We then used finally for code that always runs, and saw why it must never contain a return. Lastly, we went through what to do inside a catch block. In the next tutorial, we will throw exceptions ourselves, and see the difference between throw and throwsClick to read tutorial: throw vs throws in Java with Examples.Core Java Tutorials
Checked vs Unchecked Exceptions in JavaClick to read tutorial: Checked vs Unchecked Exceptions in Java throw vs throws in Java with ExamplesClick to read tutorial: throw vs throws in Java with Examples Creating Custom Exceptions in Java with ExamplesClick to read tutorial: Creating Custom Exceptions in Java with Examples Java try-with-resources and AutoCloseable ExplainedClick to read tutorial: Java try-with-resources and AutoCloseable Explained Java Exception Handling Best PracticesClick to read tutorial: Java Exception Handling Best Practices Java Math Class: Essential Methods with ExamplesClick to read tutorial: Java Math Class: Essential Methods with Examples
Checked vs Unchecked Exceptions in JavaClick to read tutorial: Checked vs Unchecked Exceptions in Java throw vs throws in Java with ExamplesClick to read tutorial: throw vs throws in Java with Examples Creating Custom Exceptions in Java with ExamplesClick to read tutorial: Creating Custom Exceptions in Java with Examples Java try-with-resources and AutoCloseable ExplainedClick to read tutorial: Java try-with-resources and AutoCloseable Explained Java Exception Handling Best PracticesClick to read tutorial: Java Exception Handling Best Practices Java Math Class: Essential Methods with ExamplesClick to read tutorial: Java Math Class: Essential Methods with Examples