SlightlyLoony
Tera Contributor

I got a call the other day from Otzi (he and I go way back). He ran across a piece of code that just didn't make any sense to him:


var ans = undefined;
try {
      ans = otzi.process();
}
catch (err) {
      gs.log(err);
}
finally {
      if (ans === undefined)
            ans = null;
}


"What," he demanded, "does that gobbledegook mean?"

Well, Otzi, here's your answer...

There are three parts to this. First, there's the try { } block. The curly braces enclose the statements we're trying:


try {
      ans = otzi.process();
}


In Otzi's example, there's only one line inside the curly braces, but there could have been any number of lines. The code inside those curly braces will execute just like it would if it wasn't inside the curly braces, with just one difference: if something goes horribly wrong when executing that code, the next part (below) comes into play. By "horribly wrong," I mean that some kind of error occurs. For example, suppose we tried executing the code above while the variable otzi was null, or even undefined? Without the try { }, you'd get an error in the log and your script would stop. With the try { } block, something entirely different happens:


catch (err) {
      gs.log(err);
}


If an error occurs when the code inside the try { } block executes, the code inside the catch {err} block will execute. For example, if otzi was null when we ran the script, JavaScript would throw an error when it tried to execute the .process() method (it's kind of hard for null to have a .process() method!). When JavaScript throws an error, it creates an instance of the Error class containing a message describing the error. Then it calls the catch (err) block, exactly as if catch() were a function. The code inside your catch (err) block can then read the message inside the Error instance and do whatever it needs to do. In Otzi's example, all that the catch (err) block is doing is logging the error — but it could do anything at all.

Finally, there's the finally { } block:


finally {
      if (ans === undefined)
            ans = null;
}


The first thing to know about the finally { } block is that it's optional — try { } blocks don't have to be followed by a finally { } block, and most of the time they aren't. When there is a finally { } block, the code inside of it will be executed no matter what happens when executing the code inside the catch { } block. In Otzi's example, the finally { } block is simply ensuring that the ans variable ends up defined: even if an error occurs, even if an undefined value is returned.

When the finally { } block finishes executing (or when the catch { } block finishes, if there is no finally { } block), the script keeps on executing. This is really the most important thing of all about using a try { }/catch { } construct: it's a way for your code to take a lickin' and keep on tickin'. For any situation where an error could occur, but isn't catastrophic (and therefore doesn't warrant aborting the script's execution), the try { }/catch { } construct is your friend.

A couple more details worth knowing:

If your script is calling Java code (whether through a Packages.xxx call or through a Java class exposed as a JavaScript class), and that code throws a Java exception (a mechanism within Java that's very much like the JavaScript try { }/catch { } construct), then JavaScript will turn that Java exception into a JavaScript Error and throw it. Bottom line: you can catch one of these error just like you can catch a JavaScript Error.

JavaScript doesn't have a monopoly on the ability to throw an error — your own code can do it. Here's a trivial example:


var x = 0;
try {
      gs.log(digits(x));
}
catch (err) {
      gs.log(err);
}

// return the number of integer digits in a positive number...
function digits(arg) {
      if (arg <= 0)
              throw new Error('Argument must be positive!');
      return 1 + Math.floor(Math.LOG10E * Math.log(arg));
}


If x has a number greater than zero, we'll log the number of integer digits in that number. Otherwise our function will throw an error, we won't log the number of digits (which we couldn't compute), and we'll log an error instead.

Are you feeling a little more enlightened now, oh ancient Otzi?