Exception Unwinding Trace

medium Exception Handling

Problem

Level 1 calls level 2, level 2 calls level 3, and so on up to level d. Every level prints enter i, then calls the next level, and has a finally block that prints finally i. At level t (if t > 0) an exception is thrown right after enter t, with the text throw at t printed just before. The level c (if c > 0) has a catch block that prints caught at c and stops the exception; with c = 0 no level catches it and the main program prints uncaught after the unwinding. If t = 0 nothing is thrown. Print all the lines in the order they happen. Input: d, t and c (0 <= c <= t <= d).

Constraints

  • 1 <= d <= 8
  • 0 <= c <= t <= d

Examples

Input

3 3 1

Output

enter 1
enter 2
enter 3
throw at 3
finally 3
finally 2
caught at 1
finally 1

Solutions

Best approachTime O(d)Space O(d)

An exception leaves a method at once, but finally blocks of every level on the way still run, from the deepest to the highest. The catch at level c ends the travel; after it the levels above continue normally.

Same code works in Java810172125Basic features only, so nothing changes between versions.
/*
 * Problem : Trace the unwinding.
 * Input   : d, t and c.
 * Output  : The trace lines.
 * Approach: Real exceptions.
 * Time    : O(d)
 * Space   : O(d)
 * Java    : 8 or newer.
 */
import java.util.Scanner;

public class Main {
        // Step 1: Each level enters, calls the next level, and always runs its finally block.
        private static void run(int level, int d, int t, int c, java.util.List<String> out) {
            out.add("enter " + level);
            try {
                if (level == t) {
                    out.add("throw at " + level);
                    throw new IllegalStateException("boom");
                }
                if (level < d) {
                    run(level + 1, d, t, c, out);
                }
            } catch (IllegalStateException e) {
                // Step 2: Only level c handles the exception. Other levels throw it again to their caller.
                if (level == c) {
                    out.add("caught at " + level);
                } else {
                    throw e;
                }
            } finally {
                out.add("finally " + level);
            }
        }

    // This method solves the task. It receives the input and returns the answer.
    static String[] solve(long a, long b, long m) {
        java.util.List<String> out = new java.util.ArrayList<String>();
        // Step 3: The main program catches what nobody caught.
        try {
            run(1, (int) a, (int) b, (int) m, out);
        } catch (IllegalStateException e) {
            out.add("uncaught");
        }
        return out.toArray(new String[0]);
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long a = scanner.nextLong();
        long b = scanner.nextLong();
        long m = scanner.nextLong();
        System.out.println(String.join("\n", solve(a, b, m)));
    }
}
Hints (2)
  1. In which order do the finally blocks run?
  2. What happens after the catch at level c?