Copyright © 2004 O'Reilly Media, Inc. All Rights Reserved.
Essential ActionScript 2.0
By Colin Moock
June 2004
ISBN: 0-596-00652-7
More info... .
Available from booksellers or direct from O'Reilly Media, www.oreilly.com.

Cover image
This content is excerpted from the above-named O'Reilly publication, with permission, by agreement with ActionScript.org.

If an exception occurs in a try block that is nested within a catch block, and the inner try block does not have a catch block that can handle the exception, then the search for a matching catch block begins outside the outer try/catch/finally statement:

try {
  // Outer exception occurs here.
  throw new Error("Test error 1");
} catch (e:Error) {
  // Outer exception handled here.
  trace(e);  // Displays: Test error 1
  try {
    // Inner exception occurs here.
    throw new Error("Test error 2");
  } catch (e:SomeSpecificError) {
    // Inner exception is not handled here.
    trace(e);  // Never executes because the types don't match.
  }
}
// The search for a matching catch block for the inner exception starts here.

Last, if an exception occurs in a try block that is nested within a finally block, but a prior exception is already in the process of bubbling up the call stack, then the new exception is handled before the prior exception continues to bubble up.

// This method throws an exception in a finally block.
public function throwTwoExceptions ( ):Void {
  try {
    // Outer exception occurs here. Because there is no catch block for this
    // try block, the outer exception starts to bubble up,
    // out of this method.
    throw new Error("Test error 1");
  } finally {
    try {
      // Inner exception occurs here. The inner exception is
      // handled before the outer exception actually bubbles up.
      throw new Error("Test error 2");
    } catch (e:Error) {
      // Inner exception is handled here.
      trace("Internal catch: " + e);
    }
  }
}

// Elsewhere, within another method that calls the preceding method.
try {
  throwTwoExceptions( );
} catch (e:Error) {
  // The outer exception, which has bubbled up from throwTwoExceptions( ),
  // is handled here.
  trace("External catch: " + e);
}


// Output (notice that the inner exception is caught first):
Internal catch: Test error 2
External catch: Test error 1

If, in the preceding example, the exception thrown in the finally block had never been caught, then the interpreter would have sent it to the Output panel and aborted all other code in the call stack. As a result, the original, outer exception would have been discarded along with all code in the call stack. The following code demonstrates the preceding principle. It throws an uncaught exception from a finally statement. As a result, the exception thrown by the outer try block is discarded. To test the code, you can run it directly on a frame in the timeline.

try {
  // Outer exception occurs here.
  throw new Error("Test error 1");
} finally {
  try {
    // Inner exception occurs here.
    throw new Error("Test error 2");
  } catch (e:SomeSpecificError) {
    // Inner exception is not handled here.
    trace("internal catch: " + e); // Never executes because
                                   // the types don't match.
  }
}
// The search for a matching catch block for the inner exception starts
// here. If no match is ever found, then the Output panel displays
// "Test error 2", and the bubbling of the outer exception is aborted.

The preceding code demonstrates the effect of an uncaught exception in one scenario, but once again, it's not appropriate to allow an exception to go uncaught. In the preceding case, we should either catch the exception or revise our code so that the exception isn't thrown in the first place.