10 Lesson 8 of 8

Practice & Challenges

Test your understanding of exception handling

Predict Output Fix Errors Write Code Trace

1 Predict the Output

Read each code snippet carefully. Trace the execution flow through try, catch, and finally blocks. Predict what gets printed — and what does NOT get printed. Then reveal the answer to check your understanding.

Challenge 1 — Basic try-catch
What does this code print?
try { System.out.println("A"); int x = 10 / 0; System.out.println("B"); } catch (ArithmeticException e) { System.out.println("C"); } System.out.println("D");
Output: A, C, D
Console Output
A C D

Explanation: "A" prints first. Then 10 / 0 throws ArithmeticException. "B" is never reached because the exception occurs on the line before it. The catch block matches, so "C" prints. After the try-catch, execution continues normally and "D" prints.

Challenge 2 — try-catch-finally
What does this code print? Does it crash?
try { System.out.println("A"); int[] arr = {1, 2, 3}; System.out.println(arr[5]); System.out.println("B"); } catch (ArithmeticException e) { System.out.println("C"); } finally { System.out.println("D"); } System.out.println("E");
Output: A, D, then CRASH
Console Output
A D Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 3

Explanation: "A" prints. Then arr[5] throws ArrayIndexOutOfBoundsException. The catch block only handles ArithmeticException — it does NOT match. "C" is skipped. The finally block always runs, so "D" prints. Then the unhandled exception propagates and the program crashes. "E" is NOT printed.

Challenge 3 — Multiple catch blocks
What does this code print?
try { System.out.println("A"); String s = null; System.out.println(s.length()); System.out.println("B"); } catch (NullPointerException e) { System.out.println("C"); } catch (Exception e) { System.out.println("D"); } finally { System.out.println("E"); } System.out.println("F");
Output: A, C, E, F
Console Output
A C E F

Explanation: "A" prints. Then s.length() throws NullPointerException. "B" is skipped. The first catch matches NullPointerException, so "C" prints. The second catch (Exception) is skipped because the exception was already handled. finally always runs, so "E" prints. The program continues normally and "F" prints.

Challenge 4 — Exception Propagation
What does this code print? Trace through all three methods.
public static void main(String[] args) { try { method1(); System.out.println("A"); } catch (Exception e) { System.out.println("B"); } System.out.println("C"); } public static void method1() { try { method2(); System.out.println("D"); } catch (NullPointerException e) { System.out.println("E"); } System.out.println("F"); } public static void method2() { throw new ArithmeticException(); }
Output: B, C
Console Output
B C

Explanation: method2() throws ArithmeticException. In method1(), the catch block handles NullPointerException — that does NOT match. "D", "E", and "F" are all skipped as the exception propagates out of method1(). Back in main(), the catch block handles Exception — which IS a parent of ArithmeticException, so it matches. "B" prints. "A" is skipped. After the try-catch, "C" prints.

2 Fix the Error

Each of the following code snippets contains a compilation error related to exception handling. Identify the problem and figure out how to fix it before revealing the solution.

Challenge 5 — Checked exception not handled
This code does NOT compile. Why?
public static void main(String[] args) { Scanner sc = new Scanner(new File("data.txt")); System.out.println(sc.nextLine()); }
Compilation Error: Unhandled FileNotFoundException

Problem: new File("data.txt") passed to Scanner can throw FileNotFoundException, which is a checked exception. The compiler forces you to handle it.

Fix Option 1: Wrap in try-catch:

public static void main(String[] args) { try { Scanner sc = new Scanner(new File("data.txt")); System.out.println(sc.nextLine()); } catch (FileNotFoundException e) { System.out.println("File not found!"); } }

Fix Option 2: Add throws to main:

public static void main(String[] args) throws FileNotFoundException { Scanner sc = new Scanner(new File("data.txt")); System.out.println(sc.nextLine()); }
Challenge 6 — Wrong catch order
This code does NOT compile. Why?
try { // some code } catch (Exception e) { System.out.println("General error"); } catch (ArithmeticException e) { System.out.println("Math error"); }
Compilation Error: ArithmeticException is unreachable

Problem: Exception is the parent of ArithmeticException. The first catch block catches everything, making the second catch block unreachable. Java does not allow unreachable catch blocks.

Fix: Put the more specific exception FIRST:

try { // some code } catch (ArithmeticException e) { System.out.println("Math error"); } catch (Exception e) { System.out.println("General error"); }
Challenge 7 — throw vs throws confusion
This code does NOT compile. Can you spot the mistake?
public static void validate(int age) throws IllegalArgumentException { if (age < 0) { throws new IllegalArgumentException("Age cannot be negative"); } }
Compilation Error: Syntax error — "throws" used instead of "throw"

Problem: Inside the method body, you use throw (no 's') to actually throw an exception object. The keyword throws (with 's') is only used in the method signature to declare what exceptions a method might throw.

Fix: Change throws to throw inside the if block:

public static void validate(int age) throws IllegalArgumentException { if (age < 0) { throw new IllegalArgumentException("Age cannot be negative"); } }
Remember the Difference
throw = action (throw an exception object inside a method)
throws = declaration (declare in the method signature what exceptions it might throw)

3 Write Your Own

Now it's your turn to write code from scratch. These exercises require you to create custom exception classes and use them properly. Try to write the full solution before looking at any references.

Exercise 1 Custom Checked Exception — InvalidGradeException

Requirements
  1. Create a custom checked exception called InvalidGradeException that extends Exception.
  2. Write a Student class with a setGrade(double grade) method.
  3. The setGrade method should throw InvalidGradeException if the grade is less than 0 or greater than 100.
  4. Write a main method that creates a Student object, calls setGrade with both valid and invalid values, and handles the exception with a try-catch block.
Hints
  • Your exception class needs a constructor that takes a String message and passes it to super(message).
  • Since it is a checked exception, the setGrade method must declare throws InvalidGradeException.
  • The caller must either catch or re-throw.

Exercise 2 Custom Unchecked Exception — EmptyStackException

Requirements
  1. Create a custom unchecked exception called EmptyStackException that extends RuntimeException.
  2. Write a simple Stack class that uses an array internally with push(int value) and pop() methods.
  3. The pop method should throw EmptyStackException if the stack is empty.
  4. Write a main method that pushes a few values, pops them all, and then tries to pop one more time to trigger the exception.
Hints
  • Since it extends RuntimeException, the pop method does NOT need to declare throws.
  • Use a top variable (initialized to -1) to track the top index of the stack.
  • In pop(), check if (top == -1) and throw your exception.

4 Code Tracing

This is the toughest challenge. Multiple methods, nested try-finally blocks, and exception propagation all in one. Trace through carefully, step by step.

Challenge 8 — Complex Propagation with finally
Trace through all three methods. What numbers are printed, and in what order?
public static void main(String[] args) { try { System.out.println("1"); a(); System.out.println("2"); } catch (Exception e) { System.out.println("3"); } finally { System.out.println("4"); } System.out.println("5"); } public static void a() throws Exception { try { System.out.println("6"); b(); System.out.println("7"); } finally { System.out.println("8"); } } public static void b() throws Exception { throw new Exception("Error in b"); }
Output: 1, 6, 8, 3, 4, 5
Console Output
1 6 8 3 4 5

Step-by-step trace:

  1. main() enters try block. Prints "1".
  2. main() calls a().
  3. a() enters its try block. Prints "6".
  4. a() calls b().
  5. b() throws Exception.
  6. Back in a()"7" is skipped. There is no catch block in a(), but the finally block runs. Prints "8".
  7. The exception propagates out of a() back to main().
  8. In main(), "2" is skipped. The catch block matches Exception. Prints "3".
  9. main()'s finally block runs. Prints "4".
  10. Execution continues after the try-catch-finally. Prints "5".
Key Insight
The finally block in a() runs even though a() has no catch block. finally always runs — whether the exception is caught locally or not. The exception still propagates after finally executes.
← Lesson 7: Custom Exceptions Module Hub →
Code Block Theme