Handling Exceptions practice questions

From OCP Java SE 21 (1Z0-830) · 19 questions on this topic

Handling Exceptions practice questions from OCP Java SE 21 (1Z0-830). This pack has 19 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 is the result of compiling and running this code? ```java public class Main { static class Conn implements AutoCloseable { public void close() { System.out.print("closed"); } } public static void main(String[] args) { Conn conn = new Conn(); conn = new Conn(); try (conn) { System.out.print("using "); } } } ```

    1. A. using closed

      This would be the output if the header accepted conn; it does not, because conn is reassigned before the try.

    2. B. using

      This also omits the close, but the code never reaches run time: the resource header is rejected at compile time.

    3. C. An exception is thrown at run time when the resource is closed

      The problem is caught by the compiler, not at run time; a reassigned variable cannot appear in the resource header at all.

    4. D. Compilation failsCorrect answer

      The header may name an existing variable only if it is final or effectively final; conn is reassigned on the line before, so javac rejects try (conn).

    Explanation

    Since Java 9 a try-with-resources header may name an already-declared variable instead of declaring a new one, but only when that variable is final or effectively final. Reassigning conn after its initializer means it is neither, so the compiler rejects the resource specification before anything runs. Declaring a fresh resource in the header, or removing the reassignment, would make it compile. (JLS 21 14.20.3.)

  2. Question 2

    Which statement about the variable declared by a multi-catch clause, such as catch (IOException | SQLException e), is correct?

    1. A. e has the type of the first alternative listed

      The static type of e is the least upper bound of all the alternatives (their most specific common supertype), not whichever is listed first.

    2. B. e may be reassigned to any Exception because its static type is Exception

      Even where the common supertype is Exception, the implicit finality still forbids reassignment.

    3. C. Each alternative type gets its own copy of the variable e

      One clause declares exactly one variable; the alternatives only widen the set of exception types it can hold.

    4. D. e is implicitly final, so it cannot be reassigned inside the catch blockCorrect answer

      The JLS makes a multi-catch parameter implicitly final, so any assignment to e inside the block is a compile-time error.

    Explanation

    A multi-catch clause declares a single exception parameter whose static type is the least upper bound of the listed alternatives. That parameter is implicitly final, so assigning to it inside the block is a compile-time error, unlike a single-type catch parameter, which is reassignable unless you mark it final yourself. This is why reassigning a multi-catch variable is a compile-error answer while the same assignment in a single-type catch is legal.

  3. Question 3

    What does this print? ```java public class Main { record Res(String name) implements AutoCloseable { Res { System.out.print("open-" + name + " "); } public void close() { System.out.print("close-" + name + " "); } } public static void main(String[] args) { try (Res db = new Res("db"); Res log = new Res("log")) { System.out.print("body "); throw new IllegalStateException(); } catch (IllegalStateException e) { System.out.print("catch "); } finally { System.out.print("finally"); } } } ```

    1. A. open-db open-log body catch close-log close-db finally

      Resources close as the try block exits, before any catch clause runs; the catch sees resources that are already closed.

    2. B. open-db open-log body close-db close-log catch finally

      Resources close in the reverse of their declaration order, so log, opened last, closes first.

    3. C. open-db open-log body close-log close-db catch finallyCorrect answer

      Resources open left to right, the body throws, log and db close in reverse order as the try block exits, and only then do catch and finally run.

    4. D. open-db open-log body catch finally close-log close-db

      The closes are not deferred past finally; they happen when the try block completes, ahead of both catch and finally.

    Explanation

    A try-with-resources statement initializes its resources left to right and closes them in reverse order as soon as the try block completes, whether normally or by an exception. A catch or finally clause attached to it behaves as if it belonged to an enclosing try, so it runs only after every resource is already closed. Here the body's exception passes through the close of log and then the close of db before the catch clause sees it, and finally runs last. (JLS 21 14.20.3.2.)

  4. Question 4

    Which two statements about the try-with-resources statement in Java 21 are correct? (Choose two.)

    1. A. A resource variable declared in the resource specification is also in scope in the catch and finally clauses of the same try statement

      Confuses lifetime with scope. A resource variable's scope is the resource specification and the try block only; naming it in catch or finally fails to compile with cannot find symbol, because by then the resource is already closed.

    2. B. If a resource's close() is declared to throw a checked exception, the try-with-resources statement must catch that exception or the enclosing method must declare itCorrect answer

      The implicit close() call is exception-checked like any other call, so a close() declared to throw a checked exception must be caught by the statement or declared by the enclosing method, otherwise javac reports an unreported exception.

    3. C. An exception thrown by close() while the try body is already throwing is discarded, and only the body's exception is ever visible to the caller

      Describes the pre-Java-7 finally idiom where the cleanup exception overwrote the real one. Try-with-resources keeps the body's exception primary and suppresses the close exception onto it, retrievable via getSuppressed(); nothing is lost.

    4. D. A try-with-resources statement is legal with no catch clause and no finally clauseCorrect answer

      The resource specification supplies the mandatory cleanup, so unlike a plain try (which needs a catch or a finally), a bare try (Res r = new Res()) { ... } compiles and runs, closing r on the way out.

    Explanation

    Why `If a resource's close() is declared to throw a checked exception, the try-with-resources statement must catch that exception or the enclosing method must declare it` is correct: the implicit call to `close()` is exception-checked like any other call. A resource whose `close()` is declared `throws IOException`, used in a try-with-resources with no matching catch and inside a `main` that declares no `throws`, is rejected by javac with `unreported exception IOException; must be caught or declared to be thrown` and the note `exception thrown from implicit call to close() on resource variable 'r'`. Add `catch (IOException e)` and the same program compiles and runs. Why `A try-with-resources statement is legal with no catch clause and no finally clause` is correct: the resource specification supplies the mandatory cleanup, so unlike a plain `try` (which needs at least one catch or a finally), `try (Res r = new Res()) { ... }` on its own compiles and runs, closing `r` on the way out. Why the others are wrong: `A resource variable declared in the resource specification is also in scope in the catch and finally clauses...` confuses lifetime with scope. The resource variable's scope is the resource specification and the try *block* only; naming it in the finally clause fails to compile with `cannot find symbol`. This is deliberate — by the time catch or finally runs, the resource has already been closed, so reading it would be a bug. `An exception thrown by close() while the try body is already throwing is discarded...` describes the pre-Java-7 finally idiom, where the cleanup exception overwrote the real one. Try-with-resources keeps the body's exception as primary and *suppresses* the close exception onto it; `getSuppressed()` returns it. Nothing is silently lost. Exam tip: two resource-variable rules travel together — the variable is implicitly final, and its scope ends with the try block. And remember that a bare `try (…) { }` is the only form of `try` that needs neither catch nor finally.

  5. Question 5

    What is the output of the following program? ```java public class Main { static int compute() { try { return 1; } finally { return 2; } } public static void main(String[] args) { System.out.println(compute()); } } ```

    1. A. 2Correct answer

      The finally block always executes, even when the try block completes abruptly with a return. When the finally block itself completes abruptly (here with `return 2`), the try statement's abrupt completion — reason R, return 1 — is discarded, and the method returns 2 (JLS §14.20.2).

    2. B. 1

      This assumes `return 1` in the try block takes precedence. A return is an abrupt completion, but it does not bypass the finally block. The finally block executes, issues its own abrupt completion (`return 2`), and that second completion replaces the first — the pending return-value of 1 is discarded (JLS §14.20.2).

    3. C. Compilation fails

      A `return` statement inside a `finally` block is syntactically valid Java and compiles without error under Java 21. A compiler may issue a warning because this pattern silently suppresses exceptions, but it is not a compile-time error.

    4. D. The output is unpredictable; behavior when `finally` contains a `return` is implementation-defined

      JLS §14.20.2 precisely specifies this behavior: when the finally block completes abruptly, the try statement adopts the finally block's abrupt-completion reason, discarding the try block's. This is not implementation-defined; every conforming Java 21 JVM must behave identically.

    Explanation

    When a try block and its finally block both complete abruptly, the JLS specifies that the try statement as a whole adopts the finally block's abrupt-completion reason, discarding whatever abrupt completion the try block was about to propagate. A `return` inside a finally block is an abrupt completion, so it takes precedence over any `return`, `throw`, or `break` originating in the try block. This is why returning from a finally block is considered an error-prone pattern: it silently discards not only the try's return value but also any exception that was propagating through the frame.

  6. Question 6

    A try-with-resources statement whose body throws and whose close() throws is itself wrapped in a try that has a finally clause which also throws. What does this program print? ```java public class Main { static class Res implements AutoCloseable { @Override public void close() { throw new IllegalStateException("close"); } } public static void main(String[] args) { try { try (Res r = new Res()) { throw new RuntimeException("body"); } finally { throw new IllegalArgumentException("finally"); } } catch (Throwable t) { StringBuilder sb = new StringBuilder(t.getMessage()); for (Throwable s : t.getSuppressed()) { sb.append(" +").append(s.getMessage()); } System.out.println(sb); } } } ```

    1. A. body +close

      Assumes the exception from finally is thrown away and the original survives. The opposite is true — the last exception thrown wins, so the finally exception replaces `body` and its suppressed `close`.

    2. B. body +close +finally

      Treats suppression as an accumulator that collects every exception raised in the statement. Only close() suppresses into the in-flight exception; the finally exception replaces it rather than being added.

    3. C. finallyCorrect answer

      close() throwing while `body` is in flight is suppressed into it, but the finally clause then throws, and a finally that completes abruptly REPLACES the in-flight exception — discarding `body` and its suppressed `close` — so the catch sees only IllegalArgumentException("finally") with an empty suppressed array.

    4. D. finally +body

      Assumes a finally clause suppresses the exception it displaces, the way try-with-resources does. Suppression belongs only to the resource-closing machinery; a finally that throws silently discards the previous exception, so `body` is not attached.

    Explanation

    Trace: the body throws `RuntimeException("body")`. The resource is closed, `close()` throws `IllegalStateException("close")`, and because a primary exception is already in flight the close exception is *suppressed* into it — at this instant the exception leaving the try-with-resources block is `body` carrying `close` in its suppressed array. Then the `finally` clause runs and throws `IllegalArgumentException("finally")`. A finally clause that completes abruptly by throwing does not suppress and does not chain: it *replaces* the in-flight exception, and the whole `body` object — including the suppressed `close` hanging off it — is discarded. The outer catch therefore sees only the `IllegalArgumentException`, whose message is `finally` and whose suppressed array is empty. Why the others are wrong: `body +close` assumes the exception from finally is thrown away and the original survives — the opposite is true; the last exception to be thrown wins. `finally +body` encodes the tempting but false symmetry that a finally clause suppresses the exception it displaces, the way try-with-resources does. Suppression is a mechanism of the resource-closing machinery only; nothing in the language attaches the discarded exception to the one thrown by finally. `body +close +finally` treats suppression as an accumulator that collects every exception raised anywhere in the statement. Exam tip: two different rules sit side by side here. `close()` throwing while an exception is in flight ⇒ *suppressed*, recoverable via `getSuppressed()`. `finally` throwing while an exception is in flight ⇒ *discarded silently*, unrecoverable. That silent loss is exactly why try-with-resources was added.

  7. Question 7

    What is the result of compiling and running this program? ```java public class Main { static void load(String key) throws Exception { if (key.isEmpty()) { throw new Exception("empty key"); } System.out.println("loaded " + key); } public static void main(String[] args) { try { load(""); } catch (RuntimeException e) { System.out.println("caught " + e.getMessage()); } finally { System.out.println("done"); } } } ```

    1. A. Compilation fails because a catch of RuntimeException cannot be paired with a finally clause

      Invents a rule: any catch clause may be followed by a finally clause. The failure has nothing to do with finally.

    2. B. Compilation fails: the checked Exception thrown by load is neither caught nor declared by mainCorrect answer

      load declares throws Exception (checked), and catch (RuntimeException) is not a supertype of Exception, so the checked exception is neither caught nor declared by main; javac reports unreported exception Exception.

    3. C. It prints caught empty key and then done

      Assumes catch (RuntimeException) catches anything thrown. It catches only RuntimeException and its subclasses, and a plain Exception is not one, so the program does not compile.

    4. D. It prints done and then terminates with an uncaught Exception

      What would happen if the program compiled, i.e. if main declared throws Exception. It assumes the catch-or-declare rule is enforced at run time rather than by the compiler.

    Explanation

    Trace: `load` declares `throws Exception`, and `Exception` is a checked exception. The catch clause names `RuntimeException`, which is not a supertype of `Exception`, so the call to `load("")` is left with a checked exception that is neither handled nor declared. `main` does not declare `throws Exception` either, so the catch-or-declare rule is broken and javac rejects the program with `unreported exception Exception; must be caught or declared to be thrown`, pointing at the call site. Why the others are wrong: `It prints caught empty key and then done` assumes a `catch (RuntimeException e)` clause catches anything thrown — it catches only `RuntimeException` and its subclasses, and a plain `Exception` is not one. `It prints done and then terminates with an uncaught Exception` is what would happen *if* the program compiled, i.e. if `main` declared `throws Exception`. It encodes the belief that the catch-or-declare rule is enforced at run time rather than by the compiler. `Compilation fails because a catch of RuntimeException cannot be paired with a finally clause` invents a rule: any catch clause may be followed by a finally clause. The failure has nothing to do with `finally`. Exam tip: to compile, every checked exception a statement can throw must be handled by an enclosing catch of a supertype, or declared in the enclosing method's `throws` clause. Catching a *subtype* of what is thrown (here `RuntimeException` against `Exception`) never satisfies the rule — but be careful with the reverse trap: catching `Exception` when only `IOException` is thrown is always legal.

  8. Question 8

    What is the result of compiling and running the following program? ```java public class Main { public static void main(String[] args) { try { throw new ArithmeticException("divide by zero"); } catch (ArithmeticException | IllegalArgumentException e) { e = new ArithmeticException("reassigned"); System.out.println(e.getMessage()); } } } ```

    1. A. divide by zero

      This assumes the assignment to `e` is silently discarded and the original exception object is retained. Java does not silently suppress writes to a final variable — such an assignment is a compile-time error, so the program never runs.

    2. B. Compilation failsCorrect answer

      A catch parameter in a multi-catch clause is implicitly final; the compiler rejects any assignment to it (JLS §14.20). The catch clause header is valid — `ArithmeticException` and `IllegalArgumentException` are siblings and neither is a subtype of the other — but the assignment `e = new ArithmeticException(...)` inside the block is a compile-time error.

    3. C. reassigned

      This assumes a multi-catch parameter behaves like an ordinary single-catch parameter that can be freely reassigned. It cannot: the spec makes multi-catch parameters effectively final, so the assignment is a compile-time error regardless of what the new value is.

    4. D. An `ArithmeticException` propagates uncaught

      `ArithmeticException` and `IllegalArgumentException` are both direct subclasses of `RuntimeException` and neither is a subtype of the other, so the multi-catch header is valid and would catch the thrown exception if the code compiled. The compile error comes from the assignment to `e`, not from the catch clause structure.

    Explanation

    In a multi-catch clause, the catch parameter is implicitly declared final; any assignment to it inside the catch block is a compile-time error (JLS §14.20). This constraint does not apply to ordinary single-exception catch clauses, whose parameters can be reassigned freely. The prohibition exists because the inferred type of a multi-catch parameter is the union of the alternative types, and allowing reassignment would undermine the type-safety guarantees the compiler provides at that union type. The multi-catch combination itself is legal — the spec only forbids alternatives where one is a subtype of another — so the error is confined to the assignment statement, not to the catch clause header.

Practise all 19 Handling Exceptions questions

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

Open OCP Java SE 21

Other topics in this pack