每种编程语言都会支持控制语句,来改变程序的执行顺序。
以C语言为例,来说明一下。
正常程序的执行,都是一条语句接着一条语句,按顺序执行。
可实际情况中,根据程序的执行情况来进行判断,决定继续执行哪些语句,这就出现了if-else语句,对应着底层汇编语言的跳转指令。
if语句会判断一个条件表达式,当条件满足值为真时,执行if后面的语句块,当条件不满足,则执行else里面的语句块。
除了条件分支的程序执行结构,还需要一种重复执行的结构,用来处理需要重复执行的情况。
先出现的是while语句,判断一个条件,如果条件为真就执行一组语句块,执行完后继续判断这个条件,不断循环,直到条件为假。
在while语句之后,因为经常出现要执行固定次数的循环,所以又出现了for语句,也用来执行循环功能。
作为程序的基本组成单位,一个简单函数的流程图如下:
对于这种最理想的情况,一个函数要完成某个任务,需要若干步骤来执行语句,最后得到正确的结果。
但正常情况下,函数执行的过程中,并不是一帆风顺,会出现异常或错误情况,如下图所示:
根据上面的流程图,一个函数的操作,不会一直沿着最理想的路径,当出现异常情况就会改变程序的执行顺序。
上面的流程图的典型例子如下:
#include <stdio.h>
#include <stdlib.h>
bool fileOperate () {
FILE * fp;
int ret;
fp = fopen ("file.txt", "w+");
if(fp != NULL) {
return false;
}
ret = fprintf(fp, "%s %s %s %d", "We", "are", "in", 2012);
if(ret < 0) {
fclose(fp);
return false;
}
fclose(fp);
return true;
}
这个函数要做的是对一个文件进行操作。
第一步要打开一个文件,这是申请了外部资源。然后要判断打开操作是否正确,如果不正确,则直接返回false,表明函数执行不成功。
第二步,对文件进行操作,如果操作不成功,就要关闭这个文件,然后返回false。
如果前面执行都成功了,则关闭文件,并返回true。
这时我们就可以看到,如果只关注正确的程序执行路径,函数会更简洁。但当考虑了各种执行中可能出现的错误情况,就会使程序更加复杂。
这个例子函数,只返回了true和false两种情况,有时需要返回更多的执行结果信息,比如是哪种错误造成了执行终止。
并且,根据不同的错误情况,调用者也要进行相应的处理。
这就给程序的设计带来了更多的复杂性和工作量,对整个程序的控制流有很大的影响。
语言设计者自然考虑到了这种情况,所以C++或Java等高级语言,都引入了异常机制。
程序员只需要关注正常的程序执行逻辑的设计工作,而关于程序执行中出现的异常,则有特殊的控制流来处理。
当出现异常时,程序会直接向上层调用者返回,并携带一个异常对象,用来保存当前的异常状态信息。知道返回到最顶层,或者能够捕获这个异常的调用者为止。
使用这种技术手段,就保证了正常逻辑和异常逻辑的分离,异常发生和异常处理的分离。