异常

来源:互联网 发布:日光月美新域名 编辑:程序博客网 时间:2024/06/08 09:44

异常

异常是把代码中的错误或异常时间传递给调用方代码的一种特殊手段。如果在一个子程序中遇到了预料之外的情况,但不知道如何处理的话,它就可以抛出一个异常。对出错的前因后果不甚了解的代码。可以把控制权交给系统中其他能更好地解释错误并采取措施的部分。

异常的基本结构是:子程序使用 throw 抛出一个异常对象,再被调用链上层其他子程序的try - catch 语句捕获。

关于异常的一些建议:

  1. 用异常通知程序的其他部分,发生了不可忽略的错误。异常机制的优越之处在于它能提供一种无法被忽略的错误通知机制。其他的错误处理机制有可能会导致错误在不知不觉中向外扩散,而异常消除了这种可能。
  2. 只在正真例外的情况下才抛出异常。异常的应用情形跟断言相似,都是用来处理那些不仅罕见甚至永远不该发生的情况。异常需要你做出一个取舍:一方面它是一种用来处理预料之外的情况的途径,另一方面程序的复杂度会因此增加。由于调用子程序的代码需要了解被调用代码中肯抛出的异常,因此异常弱化了封装性。这与软件额首要技术革命——管理复杂度——是背道而驰的。
  3. 不能用异常来推卸责任。如果某种错误情况可以在局部处理,那就应该在局部处理它。不要把本来可以在局部处理掉的错误当成一个未被捕获的异常抛出去。
  4. 避免在构造函数和析构函数中抛出异常。
  5. 在恰当的抽象层次抛出异常。子程序应在其接口中展现出一致的抽象,类也是如此。抛出的异常也是程序接口的一部分,和其他具体的数据类型一样。
    class Employee{    ...   public TaxId GetTaxId() throws EOFException{    ...   }}
    该处理将更底层的 EOFException 异常返回给了她的调用方,从而暴露了自身的一些实现细节。这就使得子程序的调用方代码不是与 Employee 类的代码耦合,而是与比 Employee 类层次更低的抛出 EOFException 异常的代码耦合起来了。这样做既破坏了封装性,也减低了代码的智力上的可管理性。
    class Employee{    ...   public TaxId GetTaxId() throws EmployeeDataNotAvailable{    ...   }}
    如此充分地保持了接口的抽象性。
  6. 在异常消息中加入关于导致异常发生的全部信息。
  7. 避免使用空的 catch 语句。有时你试图敷衍一个不知道该如何处理的异常。偶尔你也可能会遇到某个较低层次上的异常,它确实无法变现为调用方抽象层次上的异常。如果确实如此,至少需要写清楚为什么采用空的 catch 语句是可行的。你也可以用注释或向日志文件中记录信息来对这一情况进行文档化。
  8. 了解所用函数库可能抛出的异常。未能捕获由函数库抛出的异常将会导致程序崩溃。如果函数库没有说明它可能抛出哪些异常,可以通过编写一些原型代码来演练该函数库,找出可能发生的异常。
  9. 考虑创建一个集中的异常报告机制。这个集中报告机制能够为一些与异常有关的信息提供一个集中的存储,如所发生的异常种类,每个异常该如何处理以及如何格式化异常消息等。优点在于能把错误处理的职责集中到一起,从而让调试工作更为简单。而代价则是整个程序都要知道这个集中点并与之紧密耦合。
  10. 把项目中对异常的使用标准化。为了保持异常处理尽可能便于管理,你可以用以下几种途径把对异常的使用标准化:1.如果你在用一种像 C++ 一样的语言,其中允许抛出多种多样的对象,数据以及指针的话,那么就应该为到底可以抛出哪种种类的异常建立一个标准。为了与其他语言相兼容,可以考虑只抛出从 std :: exception 基类派生出的对象。2.考虑创建项目的特定异常类,它可以用作项目中所有可能抛出的异常的基类。这样就能把记录日志,报告错误等操作集中起来并标准化。3. 规定在何种场合允许代码使用 throw - catch 语句在局部对错误进行处理。4. 规定在何种场合允许代码抛出不在局部进行处理的异常。5. 确定是否要使用集中的异常报告机制。6. 规定是否允许在构造函数和析构函数中使用异常。
  11. 有些程序员用异常来处理错误,只是因为他所用的编程语言提供了这种特殊的错误处理机制。你心理应该自始至终考虑各种各样的错误处理机制:在局部处理错误,使用错误码来传递错误,在日志文件中记录调试信息,关闭系统或其他的一些方式等。仅仅因为编程语言提供了异常处理机制而使用异常,是典型的 “为用而用”,这也是典型的 “在一种语言上编程” 而非 “深入一种语言去编程” 的例子。
原创粉丝点击