9.4 The finally Block & Common Runtime Exceptions

Key Takeaways

  • The finally block executes deterministically after try and catch blocks, guaranteeing resource cleanup whether an exception occurred, was caught, or remained unhandled.
  • Even when a try or catch block executes a return, break, or continue statement, the finally block still executes before control transfers back to the caller.
  • The sole programmatic mechanism that prevents a finally block from executing is invoking System.exit(int status), which abruptly terminates the entire JVM process.
  • The 1Z0-811 exam heavily tests five standard runtime exceptions: NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException, and NumberFormatException.
  • Integer division by zero (10 / 0) throws an unchecked ArithmeticException, whereas floating-point division by zero (10.0 / 0.0) yields Infinity or NaN without throwing any exception under IEEE 754 rules.
Last updated: September 2026

9.4 The finally Block & Common Runtime Exceptions

[!NOTE] Exam Focus: Serving Oracle's "handle common exceptions thrown" objective, this section requires candidates to understand the deterministic execution guarantees provided by the finally block, predict console output across diverse execution and return statement paths, recognize the sole programmatic scenario where finally will not execute (System.exit()), and identify standard unchecked runtime exceptions (NullPointerException, ArithmeticException, ArrayIndexOutOfBoundsException, ClassCastException, NumberFormatException) by inspecting exam code snippets.

Robust applications must ensure that critical system resources—such as open file descriptors, database connections, and network sockets—are deterministically released even when unforeseen runtime errors occur. Java fulfills this architectural requirement through the finally block. In addition, the 1Z0-811 exam expects candidates to instantly recognize standard Java runtime exceptions and understand subtle edge cases such as integer versus floating-point division by zero.


1. The finally Block: Deterministic Cleanup

The finally block is designed to hold mandatory cleanup code that must execute regardless of whether the guarded code in the try block succeeded, encountered a caught exception, or encountered an unhandled exception.

Syntactic Rules for try-catch-finally

A try block cannot stand alone. Valid syntactic structures include:

  1. try followed by one or more catch blocks (standard error handling).
  2. try followed by a finally block (guaranteed cleanup without local catch).
  3. try followed by one or more catch blocks and a finally block (full handling and cleanup).
try {
    // Guarded operations
} catch (SpecificException e) {
    // Handler
} finally {
    // Cleanup: ALWAYS executes
}

The finally Execution Guarantee

The finally block provides an absolute execution guarantee under four distinct execution conditions:

Condition 1: Normal Execution (No Exceptions Thrown)

try {
    System.out.print("A");
} catch (Exception e) {
    System.out.print("B");
} finally {
    System.out.print("C");
}
System.out.print("D");
// Output: ACD

"A" executes cleanly. The catch block is bypassed. finally executes, printing "C". Execution continues normally, printing "D".

Condition 2: Exception Thrown and Caught

try {
    System.out.print("A");
    int x = 10 / 0; // Throws ArithmeticException!
    System.out.print("B"); // Skipped!
} catch (ArithmeticException e) {
    System.out.print("C");
} finally {
    System.out.print("D");
}
System.out.print("E");
// Output: ACDE

"A" prints. Division by zero throws ArithmeticException. Statement "B" is aborted. The catch block executes, printing "C". finally executes, printing "D". Normal execution resumes past the construct, printing "E".

Condition 3: Exception Thrown but NOT Caught

try {
    System.out.print("A");
    String s = null;
    s.length(); // Throws NullPointerException!
    System.out.print("B");
} catch (ArithmeticException e) {
    System.out.print("C"); // Does not match!
} finally {
    System.out.print("D");
}
System.out.print("E"); // Never reached!

"A" prints. NullPointerException is thrown. The catch (ArithmeticException) does not match. finally executes anyway, printing "D". Then, the unhandled NullPointerException propagates out of the method, terminating the thread. Statement "E" is never reached.

Condition 4: Return Statement Inside try or catch

Even if a try or catch block executes a return, break, or continue statement, the finally block still executes before control is returned to the caller:

public static int compute() {
    try {
        return 10;
    } finally {
        System.out.print("FinallyExecuted ");
    }
}
// Invoking compute() prints 'FinallyExecuted ' and returns integer 10.

When return 10; is reached, the JVM evaluates the return value (10) and stores it in a temporary register. Before transferring control back to the caller, execution branches to the finally block. Once finally finishes, the method returns 10.


2. The Sole Exception to finally: System.exit()

[!CAUTION] The Sole Programmatic Exception: There is only one programmatic mechanism in the Java language that prevents a finally block from executing: invoking System.exit(int status).

try {
    System.out.print("A");
    System.exit(0); // Halts JVM immediately!
    System.out.print("B");
} finally {
    System.out.print("C"); // WILL NOT EXECUTE!
}
// Output: A

When System.exit() is invoked, the Java Virtual Machine terminates the entire process immediately. Normal control flow ceases: statement "B" is skipped, and the finally block ("C") is completely bypassed. Non-programmatic events that abort finally include sudden loss of host electrical power or an operating system kill -9 signal.


3. High-Yield Standard Runtime Exceptions

The 1Z0-811 examination tests your ability to inspect code snippets and identify standard runtime exceptions belonging to java.lang:

A. NullPointerException (NPE)

Thrown when an application attempts to dereference an object reference that currently holds null. Triggers include:

  • Calling an instance method on a null reference: String s = null; s.toUpperCase();
  • Accessing or modifying an instance field on a null reference: Person p = null; p.name = "Alice";
  • Accessing the length of an uninitialized array reference: int[] arr = null; int len = arr.length;
  • Accessing or modifying an element of a null array: int[] arr = null; arr[0] = 5;
  • Unboxing a null wrapper object: Integer boxed = null; int val = boxed; (throws NPE during automatic unboxing!)

B. ArithmeticException

Thrown when an exceptional arithmetic condition occurs during mathematical computation. In Java, this occurs exclusively during integer division or integer remainder operations where the divisor is zero:

int x = 10 / 0; // Throws java.lang.ArithmeticException: / by zero
int y = 10 % 0; // Throws java.lang.ArithmeticException: / by zero

[!WARNING] The Floating-Point Division Exam Trap: Java strictly adheres to the IEEE 754 standard for floating-point arithmetic. Consequently, floating-point division by zero NEVER throws an ArithmeticException! Instead, it evaluates to special floating-point values:

double d1 = 10.0 / 0;   // Evaluates to positive Infinity (Double.POSITIVE_INFINITY)
double d2 = -10.0 / 0;  // Evaluates to negative -Infinity (Double.NEGATIVE_INFINITY)
double d3 = 0.0 / 0.0;  // Evaluates to NaN (Not-a-Number, Double.NaN)

If an exam question divides a float or double by 0 or 0.0, no exception is thrown!

C. ArrayIndexOutOfBoundsException

Thrown when an array is accessed with an illegal index that is either negative or greater than or equal to the array length:

int[] scores = {90, 85, 92}; // Valid indices: 0, 1, 2 (length is 3)
int a = scores[-1];          // Throws ArrayIndexOutOfBoundsException: -1
int b = scores[3];           // Throws ArrayIndexOutOfBoundsException: 3

A classic exam trap involves standard for loops using <= instead of <:

for (int i = 0; i <= scores.length; i++) { // BUG: On last iteration, scores[3] throws exception!
    System.out.println(scores[i]);
}

D. IndexOutOfBoundsException

The superclass of ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. It is thrown by collection classes like java.util.ArrayList when accessing elements with an invalid index:

ArrayList<String> list = new ArrayList<>();
list.add("Java");
String item = list.get(1); // Throws IndexOutOfBoundsException: Index: 1, Size: 1

E. ClassCastException

Thrown when code attempts to cast an object reference to a subclass type of which the instance is not actually an instance:

Object obj = "Hello World"; // Heap object is java.lang.String
Integer number = (Integer) obj; // Throws java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

Note that this code compiles cleanly because Object is the superclass of both String and Integer, but the cast fails dynamically at runtime.

F. NumberFormatException

A subclass of IllegalArgumentException. Thrown by wrapper class parsing methods (such as Integer.parseInt() or Double.parseDouble()) when the input String does not contain a parsable numeric format:

int a = Integer.parseInt("123");   // Valid: returns 123
int b = Integer.parseInt("12.34"); // Throws NumberFormatException (decimal not allowed for int!)
int c = Integer.parseInt("abc");   // Throws NumberFormatException
int d = Integer.parseInt("");      // Throws NumberFormatException
Exception NamePackageSuperclassPrimary Trigger
NullPointerExceptionjava.langRuntimeExceptionCalling method or reading field on null
ArithmeticExceptionjava.langRuntimeExceptionInteger division or modulo by zero (x / 0)
ArrayIndexOutOfBoundsExceptionjava.langIndexOutOfBoundsExceptionArray index < 0 or >= array.length
IndexOutOfBoundsExceptionjava.langRuntimeExceptionArrayList.get() index < 0 or >= size()
ClassCastExceptionjava.langRuntimeExceptionIncompatible reference downcast
NumberFormatExceptionjava.langIllegalArgumentExceptionFailed string-to-number parsing (parseInt("xyz"))

4. Tracing Return Value Mechanics in try-catch-finally

When a method contains return statements in both try (or catch) and finally, the 1Z0-811 exam often tests the precise order of evaluation:

Case 1: Modifying Primitive Return Variables in finally

public static int getNumber() {
    int x = 5;
    try {
        return x;
    } finally {
        x = 10; // Mutates local variable x, NOT the return value!
    }
}
// Calling getNumber() returns 5!

When return x; executes, the primitive value 5 is copied into the method's return value register. The subsequent assignment x = 10; in finally updates the local variable x, but has zero effect on the already-registered return value. Thus, the method returns 5.

Case 2: Overriding Return Statements in finally

public static int getOverride() {
    try {
        return 1;
    } finally {
        return 2; // Overrides the previous return!
    }
}
// Calling getOverride() returns 2!

Placing an explicit return statement inside a finally block completely discards and overrides any prior return statement executed in the try or catch block. While considered a code smell in production, this behavior frequently appears on certification exams.

Loading diagram...
finally Block Execution Paths and Common Exception Triggers
Test Your Knowledge

Consider the following complete method:

public static void evaluate() {
    try {
        System.out.print("A");
        System.exit(0);
        System.out.print("B");
    } catch (Exception e) {
        System.out.print("C");
    } finally {
        System.out.print("D");
    }
    System.out.print("E");
}
What is printed to the console when evaluate() is invoked?

A
B
C
D
Test Your Knowledge

Consider the following two variable declarations in a Java method:

int x = 10 / 0;
double y = 10.0 / 0;
What happens when this code is executed?

A
B
C
D
Test Your Knowledge

Consider the following Java code snippet:

Object obj = "123";
Integer num = (Integer) obj;
What happens when this code is compiled and executed?

A
B
C
D
Congratulations!

You've completed this section

Continue exploring other exams