四. 解读五个异常处理语句的应用教训
笔者结合本次项目教训谈谈JAVA异常处理的五个关键语句:try,catch,throw,throws,finally。希望能与大家分享在本次项目开发遇到的问题和总结一些经验教训。
4.1 Try和catch的教训
try语句用{}指定了一段代码,该段代码可能会抛弃一个或多个异常。catch语句的参数类似于程序的声明,包括一个异常类型和一个异常对象。异常类型必须为Throwable类的子类,它指明了catch语句所处理的异常类型,异常对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的程序。
JAVA运行时系统从上到下分别对每个catch语句处理的异常类型进行检测,直到找到类型相匹配的catch语句为止。这里类型匹配指catch所处理的异常类型与生成的异常对象的类型完全一致或者是它的父类。因此,catch语句的排列顺序应该是从特殊到一般。也可以用一个catch语句处理多个异常类型,这时它的异常类型参数应该是这多个异常类型的父类,程序设计中要根据具体的情况来选择catch语句的异常处理类型。
异常被异常处理程序捕获和处理,异常处理程序紧接在try块后面,且用catch关键字标记,因此叫做“catch块”。如果一个程序使用了异常规范,我们在调用它时必须使用try-catch结构来捕获和处理异常规范所指示的异常,否则编译程序会报错而不能通过编译。这正是JAVA的异常处理的杰出贡献,它对可能发生的意外及早预防从而加强了代码的健壮性。
在这次项目中得到一个教训是不要用一个catch语句捕获所有的异常和试图处理所有可能出现的异常。一个程序中可能会产生多种不同的异常,我们可以设置多个异常抛出点来解决这个问题。异常对象从产生点产生后,到被捕捉后终止生命的全过程中,实际上是一个传值过程,所以我们需要根据实际需要来合理的控制检测到异常的个数。catch语句表示我们预期会出现某种异常,而且希望能够处理该异常。我们建议在catch语句中应该尽可能指定具体的异常类型,必要时使用多个catch,用于分别处理不同类的异常。实际上绝大多数异常都直接或间接从JAVA.ang.Exception派生。例如我们想要捕获一个最明显的异常是SQLException,这是JDBC操作中常见的异常。另一个可能的异常是IOException,因为它要操作OutputStreamWriter。显然,在同一个catch块中处理这两种截然不同的异常是不合适的。如果用两个catch块分别捕获SQLException和IOException就要好多了。这就是说,catch语句应当尽量指定具体的异常类型,而不应该指定涵盖范围太广的Exception类。
在此项目另一个教训是初级开发人员总喜欢把大量的代码放入单个try块,这个坏习惯使我们在测试和分析问题过程中花费了大量的时间。把大量的代码放入单个try块,然后再在catch语句中声明Exception,而不是分离各个可能出现异常的段落并分别捕获其异常。这种做法为分析程序抛出异常的原因带来了困难,因为一大段代码中有太多的地方可能抛出Exception。程序的条理性和可阅读性也会变得非常差,因此我们需要尽量减小try块的体积。
异常处理中还有一种特殊情况---RuntimeException异常类,这个异常类和它的所有子类都有一个特性,就是异常对象一产生就被JAVA虚拟机直接处理掉,即在程序中出现throw 子句的地方便被虚拟机捕捉了。因此凡是抛出这种运行时异常的程序在被引用时,不需要用try…catch语句来处理异常。
异常处理语句的一般格式是:
try ...{
// 可能产生异常的代码
}
catch (异常对象 e) ...{
//异常 e的处理语句
}catch (异常对象 e1) ...{
//异常 e的处理语句
}catch (异常对象 e2) ...{
//异常 e的处理语句
}
