• Object Pascal 语法之异常处理


    http://www.cnblogs.com/spider518/archive/2010/12/30/1921298.html

    3 结构化异常处理

    结构化异常处理(SHE)是一种处理错误的手段,使得应用程序能够从致命的错误中很好地恢复。

    异常的来源
      在Delphi的应用程序中,下列的情况都比较有可能产生异常。  
      (1)文件处理  
      (2)内存分配  
      (3)Windows资源 
      (4)运行时创建对象和窗体  
      (5)硬件和操作系统冲突


    在早期的Delphi 中,异常是由Object Pascal 语言来处理的;从Delphi 2 开始,异常成为Win32 API 的一部分。用Object Pascal 来处理异常比较简单,因为异常中包含了错误的位置和特征性信息,这使得异常的使用和实现与普通的类一样。当一个错误或一些其他事件中止了程序的正常运行,系统就会抛出一个异常。


    Delphi 中包含了一些预定义的通用的程序错误异常,例如内存不足、被零除、数字上溢和下溢以及文件的输入输出错误,程序开发人员可以定义自己的异常类来适应程序的需要。通过Delphi 的异常处理机制,可以捕获这个异常并进行处理。异常实际上可以是一些对象,也可以是任何类的一个实例。通常程序开发人员总是自己定义一个从Exception 类派生出的异常类,其定义的方法与普通类的定义方法基本一致。Exception 类是在SysUtils 单元中定义的。如果一个程序的Uses 语句中包含了SysUtils 单元,发生运行错误时就会抛出一个异常。可以利用类的继承性将一组异常组合成一个系列。例如在SysUtils 单元中就定义了有关数学方面的一组异常类:

    type
        EMathError = class(Exception);
        EInvalidOp = class(EMathError);
        EZeroDivide = class(EMathError);
        EOverflow = class(EMathError);
        EUnderflow = class(EMathError);

    有时在异常类中还定义一些字段、属性和方法,通过它们可以传达一些错误信息。例如:

    type
        EInOutError = class(Exception)
            ErrorCode: Integer;
        end;
    3.1 Try...Except 语句和Try...Finally 语句

    在Try...Except 语句中可以进行抛出异常和处理异常的工作。Try...Except 的一般形式如下:

    try
        Statements1;
    except
        on Exception1 do HandleStatements1;
        on Exception2 do HandleStatements2;
        ...
        on ExceptionN do HandleStatementsN;
    else
        Statements2;
    end.

    对于有些操作,在异常处理部分要进行,在正常情况下也要进行。例如在正常情况下,使用完文件之后关闭文件;如果在对文件操作的过程中出现了异常,也需要关闭已经打开的文件。这时,就可以把关闭文件的过程放在Try...Finally 语句的Finally 部分,不管Try 部分的操作是否正常,都要进行Finally 部分的操作。

    通常Try...Finally 语句的形式如下:

    try
        statementList1
    finally
        statementList2
    end

    可以看到,Try...Finally 语句的用法与Try...Except 语句的用法很相似。StatementList1 可以为简单语句,也可以为复合语句。如果在StatementList1 中抛出了异常,程序立即转到Finally 部分;如果在StatementList1 中执行了Exit、Break 或Continue 过程而导致程序的控制离开StatementList1 部分时,程序也会跳转到Finally 部分;如果在Try 部分正常执行完毕,接着执行的还是Finally 部分。

    下面的例子介绍了在文件输入/输出时, 怎样用异常处理。可以区分与Try...Except 语句和Try...Finally 语句的用法。

    program Project1;
    
    uses
        Classes,Dialogs,SysUtils;
    
    {$APPTYPE CONSOLE}
    
    var
        F:TextFile;
        S:String;
    
    begin
        AssignFile(F,'f1.txt');
        try
            reset(F);
            try
                readln(F,s);
            finally
                CloseFile(F);
            end;
        except
            on EinOutError do
            ShowMessage('Error in FileIO');
        end;
    end.

    内层的Try...Finally 代码块用来确保文件总是关闭的,而不管是否发生了异常。这段代码的执行过程是:先执行Try 与Finally 之间的代码;如果执行完毕或出现异常,就执行Finally 与End 之间的代码;如果确实有异常发生,就跳到外层的异常处理块。这样,即使出现异常,文件也总是关闭的,并且异常总能得到处理。

    注意:在Try...Finally 块中,Finally 后面的语句不管有没有异常都被执行。因此,Finally 后面的语句不能以发生异常为前提。另外,由于Finally 后面的语句并没有处理异常,因此,异常被传递到下一层的异常处理块。外层的Try...Except 块用于处理程序中发生的异常。在Finally 中关闭文件,并且在Except 块显示一个信息,告诉用户发生了I/O 错误。这种异常处理机制比传统的错误处理方式优越,它使得错误检测代码从错误纠正代码中分离出来。这是一件好事,它会使程序更可读,使得开发人员能够集中处理程序的其他代码。


    使用Try...Finally 代码块,但不捕捉特定种类的异常是有一定意义的。当代码中使用Try...Finally块的时候,意味着程序并不关心是否发生异常,而只是想最终总是能进行某项任务。Finally 块最适合于释放先前分配的资源(例如文件或Windows 资源),因为它总是执行的(即使发生了错误)。不过,很多情况下,可能需要对特定的异常做特定的处理,这时候就要用Try...Except 块来捕捉特定的异常。

    例如:

    Program Project1;
    {$APPTYPE CONSOLE}
    
    uses
        SysUtils,Dialogs;
    
    var
        R1,R2:double;
    
    begin
        while True do begin
            try
                write('Enter a real number: ');
                readln(R1);
                write('Enter another real number: ');
                readln(R2);
                writeln('The first number divided by the Second is: ',(R1/R2):5:3);
            except
                on EInOutError do
                ShowMessage('It is not a valid number! ');
                on EZeroDivide do
                ShowMessage('Can not divide by zero! ');
            end;
        end;
    end.

    尽管在Try...Except 块中可以捕捉特定的异常,也可以用Try...Except...Else 结构来捕捉其他异常。当使用Try...Except...Else 结构的时候,应当明白Else 部分会捕捉所有的异常,包括那些并没有预料到的异常,例如内存不足或其他运行期异常。因此,使用Else 部分时要小心,能不用则不用。当进入不合格的异常处理过程中时,应当触发这个异常。

    不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。

    3.2 Raise 语句


    使用Raise 语句调用一个异常类的构造函数,并抛出一个异常。例如:raise EInOutError.Create;
    通常,Raise 语句的形式如下:

    raise object at address

    其中Object 和At Address 是可选项,Address 通常是一个指向过程或函数的指针。一个抛出的异常在处理后自动地被删除,一般不需要主动地删除一个异常对象。

     

    3.3 异常类


    异常是一种特殊的对象实例,它在异常发生时才实例化,在异常被处理后自动删除。异常对象的基类被称为Exception。在异常对象中最重要的元素是Message 属性,它是一个字符串,它提供了对异常的解释,由Message所提供的信息是根据产生的异常来决定的。

    注意:如果定义自己的异常对象,一定是要从一个已知的异常对象例如Exception 或它的派生类派生出来的,因为这样,通用的异常处理过程才能捕捉这个异常。当在Except 块中处理一个特定的异常时,可能会捕捉到该异常的派生异常。例如EMathError 是所有与数学有关的异常(例如EZeroDivide、EOverflow)的祖先。凡是没有显式地处理的异常最终将被传送到Delphi 运行期库中的默认处理过程并在此得到处理。

     

    Exception异常类

    Exception是所有异常类的基类,它并不是以’T'开头,而是以’E'开头,它的派生类也是以’E'开头的。Exception类定义于SysUtils单元中。Exception类最常用的方法是Create方法:

    Constructor Create(const Msg:string);
    Exception.Create(‘我自己创建的异常!’);

    该方法用于创建一个异常类的实例,也可以显示错误信息,也可直接用这个方法提交一个异常

    raise Exception.Create(‘我抛出的异常!’);

    例:

      try
        raise Exception.Create('我抛出的异常!');
      except
        on E: Exception do
          showmessage('异常类名称:' + E.ClassName + #13#10 + '异常信息:' + E.Message);
      end;

    Delphi7内置的异常类

    Delphi7根据异常现象的类型定义了相应的异常类,这些异常类又称为Delphi7内置的异常类。具体分为运行时库异常类对象异常类组件异常类三大类.

    运行时库异常类(RTL)

    运行时库异常类可分为以下几种:

    • 1 整数计算异常
    • 2 浮点计算异常
    • 3 硬件异常
    • 4 堆异常
    • 5 输入输出异常(I/O异常)
    • 6 字符转换异常
    • 7 类型转换异常
    • 8 哑异常

    整数计算异常

    EIntError 整数计算异常(基类)
    EDivByZero 整数除0溢处
    EIntOverFlow 整数溢出
    ERangeError 整数越界

    浮点计算异常

    EMathError 浮点计算异常(基类)
    EInvalidOp 无效浮点操作指令
    Eoverflow 浮点操作上溢
    Eunderflow 浮点操作下溢
    EZeroDivide 浮点计算除0

    硬件异常

    EProcessorException 硬件异常(基类)
    ESingleStep 应用程序产生单步中断
    Ebreakpoint 应用程序产生断点中断
    Efault 故障(继承EProcessorException,也是基类)
    EStackFault 对处理器栈段的非法访问
    EPageFault 内存管理器无法正确使用交换文件
    EGPFault 保护性错误,一般由未初始化指针或对象造成
    EInvalidOpCode 处理器遇到未定义指令


    堆异常

    EOutOfMemory 堆中没有足够的内存完成操作
    EInvalidPointer 试图访问一个堆外的指针

    I/O异常

    EInOutError DOS输入/输出错误

     

    字符转换异常

    EConvertError 数字到字符串或字符串到数
    字转换错误

    类型转换异常

    EInvalidCast 类型转换异常

    哑异常

    EAbort 调用Abort产生,不显示错误提示框

     

    对象异常类

    对象异常类是针对非组件对象引发的异常而定义的.
    对象异常类包括:

    • 1 流异常类
    • 2 打印异常类
    • 3 图形异常类
    • 4 字符串链表异常类

    流异常类

    流异常是指在程序中进行与流相关的操作时产生的异常.流异常类的基类是EStreamError,其他流异常类都直接或间接从它派生.
    派生关系见书48页图

    打印异常

    打印异常是由于应用程序向不存在的打印机发送打印命令或由于某种原因打印工作无法送到打印机时引发的.
    打印异常类为Eprinter,定义于Printers单元

    图形异常

    图形异常主要包括EInvalidGraphic 和 EInvalidGraphicOperation两个类均定义于Graphics单元

    EInvalidGraphic异常满足下列情况之一时引发:

    • 当应用程序试图向一个并不包含合法的位图,图象,元文件或用户自定义图形类型的文件中装入图象时.
    • 当应用程序试图装入不可识别扩展名的文件时
    • 当图象与LoadFromClipboardFormat或SaveToClipboardFormat中的格式不匹配时.
    • 当应用程序试图将图象的PixelFormat设为不支持的值

    EInvalidGraphicOperation异常在满足下列条件之一时发生:

    • 应用程序访问图象中不存在的扫描线时.
    • 应用程序不能成功写入图象时.
    • 应用程序在画布未处于有效状态时进行绘制.
    • 应用程序装入未知或不支持的图象格式时.
    • 应用程序将图象的PixelFormat设为不支持的值时
    • 不能分配该操作的句柄时.

    字符串链表异常

    字符串链表异常是由于用户对字符串链表进行非法操作时引发的。包括EStringListError,EListError等.由于许多部件都有一个Tstrings抽象类的属性(如Tiistbox组件的Items属性等),因而字符串链表异常在组件编程中很重要.

    EStringListError一般在字符串链表越界时产生.而EListError异常通常在以下情况下发生:

    当索引项超出链表范围时
    当字符串链表的Duplicates属性设置为dupError
    同时应用程序试图加入一个重复的字符串时.
    当向已排序的字符串链表中插入字符串时.

     

    组件异常类

    组件异常类用于响应组件异常,组件异常是由于对VCL组件进行操作时,违反了组件的使用规则及其特征而引发的,可分为两大类: 用组件异常、专用组件异常。

    通用组件异常
    常见的有非法操作异常,组件异常和资源不足异常三种类型,对应于EInvalidOpetation,EComponentError和EOutOfResource异常类.

    引发非法操作异常的原因有:

    应用程序试图对Parent属性为nil的组件进行一些需要窗口句柄的操作.
    试图对窗体拖放操作.

    引发组件异常的原因有:

    Delphi不能注册某个组件

    应用程序不能重命名某个组件

    资源不足异常被引发是由于当应用程序试图创建窗口句柄而操作系统没有多余的句柄可分配

     

    专用组件异常:许多组件都定义了相应的组件异常类.

    列出几个典型的组件异常类:

    EMenuError异常,菜单异常,是由于程序对菜单的非法操作而引发的.定义于Memus单元
    EInvalidGridOperation异常.非法的网格操作,如试图引用一个不存在的网格单元时引发.定义于Grids单元
    EDatabaseError异常.数据库异常是由于对数据库的非法操作引起的.

     

    用户自定义异常类

    创建用户自定义异常类的方法

    选择Exception作为基类,按照定义类的一般方法,建立自定义的异常类就可以了.
    如:

    type
      EMyException = class(Exception)
      //需要定义属性或方法时,写在此处即可
      end;抛出自定义异常

     

     

    异常的调试
      在Delphi IDE中,解除“Debugger Options”(可以使用菜单Tools—>Debugger Options…进行访问)中的Integrated Debugging复选框的勾选状态可以进行异常的调试。

  • 相关阅读:
    Mybatis多层嵌套查询
    UUID 唯一性实现原理
    oracle 多实例启动
    orcal启动多实例是报 ORA-00845: MEMORY_TARGET not supported onthis system
    java调用quartz 2.2.2方法总结。
    mybatis中like的使用(模糊查询)
    Orcal数据库实现主键ID自增
    spring cloud分布式关于熔断器
    spring cloud分布式健康检查
    spring cloud分布式整合zipkin的链路跟踪
  • 原文地址:https://www.cnblogs.com/ivantang/p/3824262.html
Copyright © 2020-2023  润新知