异常处理
异常是指正常情况下不会发生的所谓「例外」的情况。在大部分情况下异常和错误可以当作同义词。
异常会发生的地方
程序的任何地方都有发生异常的可能性。
发生异常的时候,异常将被「投出(throw)」。
比如说,以下的脚本将会引起错误。
例:
"3%0"!;//发生“除以0错误”的异常
虽然有像上例一样明显会发生异常的情况,但也有一些情况下,无法知道代码是否一定会发生异常。
异常的捕捉
使用 try
(尝试) 关键字和 catch
(捕捉) 关键字,可以捕捉异常。
例如说,为了捕捉上面所说的“不知道是否会发生的异常”,可以象下面这样编写代码。
例:
try//不知道是否会发生异常
{
func1();//这里有可能会发生异常
}
catch//捕捉异常
{
//当发生异常的时候,这里的代码被执行
inform("无法读取图像。");//显示信息
}
像这样在 try 代码段中编写可能会发生异常的代码,就可以在发生异常的时候执行 catch 代码段中的代码。利用这个功能,可以编写出清晰流畅的错误处理代码。
在 try 代码段中没有发生任何异常的情况下,catch 代码段不会被执行。
try 代码段中可以编写任何的代码。除了在代码段中直接发生异常的情况之外,在代码段中调用的函数,以及被函数调用的函数中发生的异常,try ... catch 代码都可以捕捉到。
发生异常的情况下,代码段剩下的执行步骤将被中断,并返回到 try 语句的位置。
如果在 catch 代码段中也发生了异常,该异常便无法在这个 catch 代码段中被捕捉。这个异常将会按照调用上下文向上回溯,如果在发生错误的 catch 代码上层存在 try 语句,则异常将在那里被捕捉。
在异常被抛出之后,程序到达 catch 块之前有发生其他异常的可能性,但这种情况下的操作未被定义。
如果异常在脚本中完全没有被捕捉到,则异常将离开脚本而被传递给应用程序,由应用程序来进行处理。
Note
一般来说,由于错误而被抛出的异常会中断脚本的执行,所以建议尽可能在可能发生错误的地方写入 try ... catch 。
异常对象
关于异常的各种各样的欣喜,都会和一个 Exception 类的对象一起被投出。这个对象被称做异常对象,可以通过 catch 语句来获取。
例如说,我们可以编写以下代码。
例:
try
{
loadImages("nothing.jpeg");//可能会发生异常的操作
}
catch(e)//利用e这个变量获取异常对象
{
//e.message是和异常一起投出的消息字符串。
//一些情况下发生异常的理由会通过这个变量说明。
inform("无法读取图像。\n"+e.message);
}
像这样,在 catch 后的括号中写入变量名,就可以利用这个变量接收异常对象。
这个变量的作用域,从 catch 后的代码段中开始,并随着程序离开这个代码段而结束。此外,这个变量不需要事先的声明。
throw 语句
在 TJS 程序中可以使用 throw
关键字投出异常。
例如,我们可以编写如下代码。
例:
functionpow2(n)
{
//计算2的n次幂,提供的n必须是正整数
if(n<0)thrownewException("不能指定负数。");
//↑发生异常
return1<<n;
}
如果给这个函数传递了类似于 -1 这样的负数,就会发生异常。投出异常可以使用类似以下的语句。
thrownewException("不能指定负数。");
new Exception("不能指定负数。")
这个语句将以字符串作为参数创建一个新的 Exception 类对象(详细请参考 Exception 类的说明)。然后将这个新创建的对象通过 throw 关键字投出。
throw 关键字能投出的对象并非一定要是 Exception 类的对象,数字也好,字符串也好,包括对函数的引用也能够被投出。但是,我们推荐投出 Exception 类,或者这个类的派生类的对象。这样,在 catch 代码段中只需要统一编写对应 Exception 类对象的代码即可。
再次投出异常
catch 可以捕捉到发生的异常,但在直接对应的 try 块的上层也有可能声明了别的 try 语句。在这种情况下,可以再次投出异常。
我们可以编写如下代码。
例:
functiontryloadimage()
{
try
{
primaryLayer.loadImages("test1.bmp");//尝试读取test1.bmp
}
catch(e)
{
inform("图像读取失败。");
throwe;//上面的信息被显示的同时,异常会被再次投出
}
}
functiontest()
{
//调用tryloadimage,如果读取图像成功则返回true
//否则返回false的函数
try
{
tryloadimage();
}
catch
{
returnfalse;
}
returntrue;
}
在这种情况下调用 test() ,并且图像读取失败,那么在 inform 方法显示出消息的同时,由于异常被再次投出,可以通过 test 函数内的 catch 代码进行捕捉。