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.

Our first exception example was overly simplistic. What happens if our method generates more than one kind of error? Are they all sent to the same catch block? Well, that's up to the developer; they certainly could be, but it's more typical and better practice for different kinds of errors to be handled by separate catch blocks. Let's examine why.

Suppose we wanted a finer-grained set of error messages in our setWidth( ) method: one for general invalid data, one for too small a width, and one for too large a width. Our revised setWidth( ) method might look like this:

public function setWidth (w:Number):Void {
if (isNaN(w) || w == null) {
throw new Error("Illegal Box dimension specified.");
} else if (w <= 0) {
throw new Error("Box dimensions must be greater than 0.");
} else if (w > Number.MAX_VALUE) {
throw new Error("Box dimensions must be less than Number.MAX_VALUE.");
}
width = w;
}

To handle the three possible error messages in our new setWidth( ) message, we might be tempted to code our try/catch/finally statement as follows:

try {
b.setWidth(someWidth);
// If we get this far, no exception occurred; proceed as planned.
trace("Width set successfully.");
} catch (e:Error) {
switch (e.message) {
case "Illegal Box dimension specified.":
trace("An error occurred: " + e.message);
trace("Please specify a valid dimension.");
break;

case "Box dimensions must be greater than 0.":
trace("An error occurred: " + e.message);
trace("Please specify a larger value.");
break;

case "Box dimensions must be less than Number.MAX_VALUE.":
trace("An error occurred: " + e.message);
trace("Please specify a smaller value.");
break;
}
}

Admittedly, that code does work, but it's fraught with problems. First, and most serious, the errors are distinguished from one another only by the text in a string that is hidden within the Box class. Each time we want to check the type of an error, we have to look inside the Box class and find the message string. Using the string for error identification across multiple methods and classes is highly prone to human error and makes our code difficult to maintain. Second, the switch statement itself is barely more readable than our original, if/else statement (the one we used before we added exceptions to the setWidth( ) method). We're not much farther ahead than we would be if we had used, say, numeric error codes instead of formal exceptions.

Fortunately, there's a formal (and elegant) way to handle multiple exception types. Each try block can have any number of supporting catch blocks. When an exception is thrown in a try block that has multiple catch blocks, the interpreter executes the catch block whose parameter's datatype matches the datatype of the value originally thrown. The datatypes of the catch parameter and thrown value are considered a match if they are identical or if the catch parameter type is a superclass of the thrown value's type.

Here's the general syntax of a try statement with multiple catch blocks:

try {
// Code that might generate an exception.
} catch (e:ErrorType1) {
// Error-handling code for ErrorType1.
} catch (e:ErrorType2) {
// Error-handling code for ErrorType2.
} catch (e:ErrorTypen) {
// Error-handling code for ErrorTypen.
}

If a throw statement in the preceding try block were to throw an expression of type ErrorType1, then the first catch block would be executed. For example, the following code causes the first catch block to execute:

throw new ErrorType1( );

If a throw statement were to pass an expression of type ErrorType2, then the second catch clause would be executed, and so on. As we learned earlier, in ActionScript the throw statement expression can belong to any datatype. However, as an OOP best practice, we should throw only instances of the Error class or one of its subclasses (this best practice follows Java, where throw can be used only with Throwable and its subclasses).

If we want to throw multiple kinds of exceptions in an application, we should define an Error sub" name="as2e-CHP-10-ITERM-3455">granularity you require (i.e., to what degree you need to differentiate among different error conditions). However, don't confuse the following discussion of how to implement granularity in error handling as an insistence that you must implement such granularity.