Handling Exceptions practice questions

From OCP Java SE 25 (1Z0-831) · 16 questions on this topic

Handling Exceptions practice questions from OCP Java SE 25 (1Z0-831). This pack has 16 questions tagged Handling Exceptions, drawn from its timed mock exams. 8 of them are worked through in full below — the question, every option, why each is right or wrong, and the explanation.

Worked examples for Handling Exceptions

  1. Question 1

    What happens when this program is compiled and run? ```java import java.io.IOException; public class Main { public static void main(String[] args) { try { throw new IOException(); } catch (Exception e) { System.out.println("ex"); } catch (IOException e) { System.out.println("io"); } } } ```

    1. A. Prints ex

      Assumes the code compiles and the first clause wins, but the unreachable second clause makes it a compile error before any output.

    2. B. Prints io

      Assumes clause selection picks the most specific type, but Java uses first-match order, not best-match, and this ordering is illegal anyway.

    3. C. Prints ex then io

      Assumes two catch blocks can both run, but at most one catch executes per try, and this code does not compile.

    4. D. Compilation fails: IOException has already been caughtCorrect answer

      catch clauses are matched top to bottom, and since IOException IS-A Exception, the preceding catch of Exception makes the later IOException clause unreachable, so javac reports 'exception IOException has already been caught' (JLS 25 §14.20.1).

    Explanation

    Catch clauses are tried in written order, so a broader type must never precede a narrower one it already covers, or the narrower clause becomes unreachable and the compiler rejects it. Order catch clauses specific to general; putting the subclass first here would compile and print io. The 'has already been caught' error is the tell-tale of a superclass listed ahead of its subclass.

  2. Question 2

    What happens when this program is compiled and run? ```java import java.io.IOException; import java.io.FileNotFoundException; public class Main { public static void main(String[] args) throws Exception { try { if (args.length == 0) throw new FileNotFoundException(); } catch (FileNotFoundException | IOException e) { System.out.println("caught"); } } } ```

    1. A. Prints caught

      Assumes the code compiles, but it never gets past javac because of the illegal multi-catch clause.

    2. B. Compilation fails: the multi-catch alternatives are related by subclassingCorrect answer

      FileNotFoundException IS-A IOException, and multi-catch alternatives must be pairwise unrelated by subtyping, so javac rejects the redundant subclass/superclass pair (JLS 25 §14.20).

    3. C. Compilation fails: a checked exception like FileNotFoundException may not appear in a multi-catch

      Checked exceptions are perfectly allowed in a multi-catch; the fault is the subclass/superclass relationship, not the checked status.

    4. D. Compiles and runs, printing nothing

      The program cannot run because compilation fails; and even if the clause were legal, args.length is 0 so it would throw and print 'caught' rather than nothing.

    Explanation

    Multi-catch alternatives must be pairwise unrelated by subtyping, because listing a subclass beside its superclass is redundant: the superclass already catches it. Here one alternative is a subclass of the other, so the compiler rejects the clause and the program never runs. Collapsing the redundant pair down to the single superclass fixes it.

  3. Question 3

    The resource's close() method, the catch clause and the finally block each write to standard output. Trace the output of this program. ```java public class Main { static class Res implements AutoCloseable { public void close() { System.out.print("close "); } } public static void main(String[] args) { try (Res r = new Res()) { System.out.print("body "); throw new IllegalStateException("x"); } catch (IllegalStateException e) { System.out.print("catch "); } finally { System.out.print("finally"); } } } ```

    1. A. body catch finally close

      Assumes close runs last like a finally action; a resource is closed as the try block completes, before any catch or finally of the same statement.

    2. B. body close catch finallyCorrect answer

      The resource is closed as soon as the try block exits abruptly, before the catch handles the exception, so the order is body, close, catch, finally.

    3. C. body catch close finally

      Assumes close runs after the catch clause; closing happens when the try block completes, ahead of the catch.

    4. D. body catch finally

      Assumes an exception thrown from the body skips closing; resources are closed whether the block completes normally or abruptly.

    Explanation

    A try-with-resources statement closes its resources as soon as the try block completes, whether normally or abruptly, and it does so before any catch or finally clause of the same statement runs. So when the body throws, the resource is closed first, then the catch handles the exception, and finally runs last.

  4. Question 4

    The second resource's constructor throws. What does this program print? ```java public class Main { static class R implements AutoCloseable { final String n; R(String n) { this.n = n; System.out.print("open" + n + " "); if (n.equals("B")) { throw new RuntimeException("ctorB"); } } public void close() { System.out.print("close" + n + " "); } } public static void main(String[] args) { try (R a = new R("A"); R b = new R("B"); R c = new R("C")) { System.out.print("body "); } catch (RuntimeException e) { System.out.print("caught " + e.getMessage() + " sup=" + e.getSuppressed().length); } } } ```

    1. A. openA openB closeA caught ctorB sup=0Correct answer

      Correct: A opens fully, then B's constructor prints openB and throws, so b is never assigned and is not closed; only the completed resource A is closed, and ctorB is caught with nothing suppressed.

    2. B. openA openB closeB closeA caught ctorB sup=0

      Assumes B counts as open because its constructor started running; a resource variable is initialized only if its initializer completes normally, so B is never closed.

    3. C. openA openB openC body closeC closeB closeA

      Assumes initialization continues past the throwing constructor and the body still runs; a throwing initializer stops the statement, skipping C and the body entirely.

    4. D. openA openB caught ctorB sup=0

      Assumes a failing initializer aborts the whole statement without closing anything; that would leak A, which is precisely what try-with-resources exists to prevent, so A is still closed.

    Explanation

    Trace: resources are initialized left to right. `new R("A")` prints `openA ` and completes, so a is a live resource. `new R("B")` prints `openB ` and then throws ctorB from inside the constructor — b is never assigned, and a resource whose initializer did not complete normally is never closed. Initialization stops there, so `new R("C")` never runs and the body never runs. The resources that were successfully opened are closed in reverse declaration order, which here is just a: `closeA `. The ctorB exception then reaches the catch clause. Nothing was suppressed, because close() on a completed normally — suppression needs a close() that throws. Output: `openA openB closeA caught ctorB sup=0`. Why the others are wrong: `openA openB closeB closeA caught ctorB sup=0` assumes B counts as open because its constructor started running; the resource variable is only considered initialized if its initializer completes normally. `openA openB caught ctorB sup=0` assumes a failing initializer aborts the whole statement without closing anything — that would leak A, which is precisely what try-with-resources exists to prevent. `openA openB openC body closeC closeB closeA` assumes initialization continues past a throwing constructor and the body still runs. Exam tip: a try-with-resources statement has three independent failure sites — initializer, body, close. An initializer that throws closes exactly the resources declared before it, in reverse order, and skips the body and every later initializer. getSuppressed() stays empty unless a close() itself throws while another exception is already in flight.

  5. Question 5

    Both the inner try block and its finally block throw. What does this program print? ```java public class Main { public static void main(String[] args) { try { try { throw new IllegalStateException("body"); } finally { throw new IllegalArgumentException("finally"); } } catch (RuntimeException e) { System.out.println(e.getMessage() + " sup=" + e.getSuppressed().length); } } } ```

    1. A. finally sup=1

      Assumes a plain try/finally attaches the displaced exception as a suppressed exception; addSuppressed is called only by the try-with-resources closing code, never by a bare finally, so the suppressed array is empty.

    2. B. finally sup=0Correct answer

      When the finally block completes abruptly by throwing, its exception replaces the pending one outright: the body's IllegalStateException is discarded (not recorded anywhere), so catch binds IllegalArgumentException("finally") with an empty suppressed array (JLS 25 14.20.2).

    3. C. body sup=0

      Assumes the first exception thrown wins; it is the last abrupt completion — the finally block's exception — that wins, so the message is `finally`, not `body`.

    4. D. body sup=1

      Combines both errors: the original exception propagating with the finally exception attached as suppressed; a bare finally neither preserves the original nor records a suppressed exception.

    Explanation

    Trace: the inner try throws IllegalStateException("body"). Before that exception can propagate, the finally block must run — and it completes abruptly by throwing IllegalArgumentException("finally"). When a finally block completes abruptly, its reason replaces the pending one outright: the body's exception is discarded, not recorded anywhere. The outer catch therefore binds the IllegalArgumentException, whose message is `finally` and whose suppressed array is empty, so the program prints `finally sup=0`. Why the others are wrong: `finally sup=1` assumes a plain try/finally attaches the exception it displaces as a suppressed exception. It does not — addSuppressed is called only by the compiler-generated closing code of a try-with-resources statement, never by a bare finally. `body sup=0` assumes the first exception thrown wins. It is the last abrupt completion that wins. `body sup=1` combines both errors: original exception propagating with the finally exception attached to it. Exam tip: a finally block that throws (or returns, or breaks) silently swallows whatever the try was doing — the classic lost-exception bug. That hazard is exactly why try-with-resources was given a suppression mechanism, and it is why suppressed exceptions show up there and nowhere else.

  6. Question 6

    What does this program print? ```java public class Main { static int f() { int x = 1; try { x = 2; throw new RuntimeException("boom"); } catch (RuntimeException e) { return x; } finally { x = 3; System.out.print("finally "); } } public static void main(String[] args) { System.out.println(f()); } } ```

    1. A. 2

      Assumes a return inside catch skips the finally block; finally runs on every exit path short of JVM termination, so "finally " is printed.

    2. B. finally 1

      Assumes the catch clause sees x as it was on entry to the try, ignoring the x = 2 that executed before the throw; x is 2 when return x runs.

    3. C. finally 2Correct answer

      Correct: return x captures the value 2 into the return slot at that instant, and the finally block's x = 3 mutates the local variable, not the already-computed return value, so f() returns 2.

    4. D. finally 3

      Assumes the pending return re-reads x after finally completes; the return expression is evaluated once, before control transfers to finally, so the later x = 3 does not change it.

    Explanation

    Trace: f() starts with x = 1. The try body sets x = 2 and throws, so the catch clause runs and evaluates return x — the value 2 is captured into the return slot at that instant. Only then does the finally block execute: it prints `finally ` and sets x = 3, but that assignment mutates the local variable, not the return value that was already computed. f() returns 2, so the program prints `finally 2`. Why the others are wrong: `finally 3` assumes the pending return re-reads x after finally completes; the return expression is evaluated once, before control transfers to finally. `finally 1` assumes the catch clause sees x as it was on entry to the try, ignoring the x = 2 that executed before the throw. `2` assumes a return inside a catch clause skips the finally block; finally runs on every exit path short of JVM termination. Exam tip: a finally block can only override a return value by executing its own return (or by throwing) — a plain assignment to the returned variable arrives too late. Reverse trap: change the finally to `return x;` and the answer becomes 3, because that second return discards the first.

  7. Question 7

    Which two of these exception types are unchecked exceptions? (Choose two.)

    1. A. NullPointerExceptionCorrect answer

      NullPointerException is a direct subclass of RuntimeException, so it is unchecked and the compiler never forces you to catch or declare it.

    2. B. java.io.IOException

      IOException extends Exception but not RuntimeException, so it is a checked exception that must be caught or declared in a throws clause.

    3. C. NumberFormatExceptionCorrect answer

      NumberFormatException extends IllegalArgumentException, which extends RuntimeException, so it is unchecked despite its I/O-sounding name.

    4. D. InterruptedException

      InterruptedException extends Exception directly, making it checked; blocking calls such as Thread.sleep force you to handle it.

    Explanation

    The unchecked exceptions are exactly RuntimeException, Error, and their subclasses. Trace each type up its hierarchy: if you reach RuntimeException or Error before Exception, it is unchecked; otherwise the compiler forces you to catch or declare it. The name is no guide, so a type that sounds I/O-related can still be a RuntimeException while IOException itself is checked.

  8. Question 8

    What does this program print? ```java public class Main { static int f() { try { throw new RuntimeException("boom"); } finally { return 42; } } public static void main(String[] args) { System.out.println(f()); } } ```

    1. A. 42Correct answer

      The finally block executes return 42, which completes the try abruptly for a new reason and discards the pending exception, so f() returns 42 (JLS 25 §14.20.2).

    2. B. Throws RuntimeException with message boom

      The exception would propagate only if the finally completed normally; the return in finally replaces the pending throw, so 'boom' is silently swallowed.

    3. C. Compilation fails: a finally block cannot contain a return statement

      A return inside finally is perfectly legal (some linters merely warn about it), not a compile error.

    4. D. 0

      0 would be a default field value; the finally explicitly returns 42, and defaults never apply to a returned literal.

    Explanation

    When a try body throws, the pending exception is held while the finally block runs. If that finally itself returns (or throws), it completes the try abruptly for a new reason and the pending exception is discarded entirely. Here the finally returns a value, so no exception ever escapes and that value is what the method returns. This silent swallowing is exactly why returning from a finally block is considered a bug.

Practise all 16 Handling Exceptions questions

OCP Java SE 25 has the full set, inside timed mock exams that mirror real exam conditions — every question with a worked explanation.

Open OCP Java SE 25

Other topics in this pack