Skip to main content

4.3 try-catch-finally Execution Flow

← Back to Chapter 4: Exception Handling

The try-catch-finally block is Java's foundational error handling construct. Understanding its detailed control flow guarantees that critical resources are never orphaned.


Execution Flow Rules​

  1. try block: Contains code that might throw an exception.
  2. catch block: This block executes only if an exception matching the parameter type is thrown.
  3. finally block: This block always executes, whether an exception occurred, was caught, or was uncaught.
try {
processPayment();
} catch (InsufficientFundsException | ExpiredCardException e) {
// Multi-catch (Java 7+): parameter 'e' is implicitly final
log.warn("Payment failed: {}", e.getMessage());
} catch (PaymentGatewayException e) {
// Broader exception caught lower in the hierarchy
log.error("Gateway outage", e);
} finally {
releaseTransactionLock(); // Guaranteed cleanup!
}

Multiple Catch blocks​

try {
// risky code
} catch (ArithmeticException e) {
// handle arithmetic problem
} catch (NullPointerException e) {
// handle null problem
} catch (Exception e) {
// handle other exceptions
}

Important rule​

The more specific exception must come first.

In this case ArithmeticException and NullPointerException are more specific than Exception.

finally​

finally is used for cleanup code.

try {
// risky operation
} catch (Exception e) {
// handle exception
} finally {
// cleanup
}

finally generally executes whether an exception occurs or not.

Can we have try without catch?​

Yes.

try {
// code
} finally {
// cleanup
}

This is valid.

But this is not valid:

try {
// code
}

A try must be followed by at least:

catch
OR
finally

Can finally be skipped?​

Normally, finally executes.

But there are exceptional situations, for example:

System.exit(0);

If the JVM terminates using System.exit(), normal finally execution does not occur.

Also, if the JVM itself crashes/terminates abnormally, there is no guarantee that finally will execute.

throw keyword​

throw is used when you want to explicitly throw an exception. It is used inside the function.

Example:

if (age < 18) {
throw new IllegalArgumentException("Age must be 18 or above");
}

Think:

throw = actually throw an exception

throws​

throws is used in a method declaration.

Example:

public void readFile() throws IOException {
// code
}

It means:

"This method may throw IOException. Whoever calls me needs to deal with it."

throw vs throws​

throwthrows
Used to actually throw exceptionDeclares possible exceptions
Used inside method/blockUsed in method signature
Throws one exception at a timeCan declare multiple exceptions
throw new Exception()throws IOException
throw = actually throw an exception
throws = declaring that this function may throw an exception