Try-finally block prevents StackOverflowError

Try running the following code:

    try {
        throw new Exception("TEST!");
    } finally {
        System.out.println("Finally");
    }

You will find that the finally block executes before throwing an Exception up to the level above it. (Output:

Finally

Exception in thread "main" java.lang.Exception: TEST! at test.main(test.java:6)

This makes sense, as finally is called right before exiting the method. This means, however, that once you get that first StackOverflowError, it will try to throw it, but the finally must execute first, so it runs foo() again, which gets another stack overflow, and as such runs finally again. This keeps happening forever, so the exception is never actually printed.

In your bar method however, as soon as the exception occurs, it is just thrown straight up to the level above, and will be printed


It doesn't run forever. Each stack overflow causes the code to move to the finally block. The problem is that it will take a really, really long time. The order of time is O(2^N) where N is the maximum stack depth.

Imagine the maximum depth is 5

foo() calls
    foo() calls
       foo() calls
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
       finally
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
    finally calls
       foo() calls
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
       finally
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
finally calls
    foo() calls
       foo() calls
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
       finally
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
    finally calls
       foo() calls
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()
       finally
           foo() calls
              foo() which fails to call foo()
           finally calls
              foo() which fails to call foo()

To work each level into the finally block take twice as long an the stack depth could be 10,000 or more. If you can make 10,000,000 calls per second, this will take 10^3003 seconds or longer than the age of the universe.


When you get an exception from the invocation of foo() inside the try, you call foo() from finally and start recursing again. When that causes another exception, you'll call foo() from another inner finally(), and so on almost ad infinitum.