Java核心技术第11章(1)

第11章  异常,断言,日志和调试

    程序必须做到以下几点:
    1.向用户通告错误
    2.保存所有的工作结果
    3.允许用户以妥善的形式退出程序

    对于异常情况,例如,可能造成程序崩溃的错误输出,Java使用一种称为异常处理(exception handing)的错误捕获机制处理.本章的第1部分将介绍Java的异常.
    在测试期间,需要进行大量的测试以验证程序操作的正确性.然而,这些检测可能非常耗时,在测试完成后也不必保留它们.因此,可以将这些检测删掉,并在其他测试需要时将它们粘贴回来,这是很乏味的事情.本章的第2部分将介绍如何使用断言来有选择地启用检测.
    当程序出现错误时,并不总是能够与用户或终端进行沟通.此时,可能希望记录下出现的问题,以备日后进行分析.本章的第3部分将讨论标准Java日志框架.

11.1    处理错误

    假设在一个Java程序运行期间出现了一个错误.这个错误可能是由于文件包含了错误信息,或者网络连接出现问题造成的,也有可能是因为使用无效的数组下标,或者试图使用一个没有被赋值的对象引用而造成的.用户期望在出现错误时,程序能够采用一些理智的行为.如果由于出现错误而使得某些操作没有完成,程序应该:
    1.返回到一种安全状态,并能够让用户执行一些其他的命令;或者
    2.允许用户保存所有操作的结果,并以适当的方式终止程序.
    做到这些很困难,其原因是检测错误条件的代码通常离那些能够让数据恢复到安全状态,或者能够保存用户的操作结果,并正常地退出程序的代码很远.异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器.为了能够在程序中处理异常情况,必须研究程序中可能会出现的错误和问题,以及哪类问题需要关注.
    1.用户输入错误
    2.设备错误
    3.物理限制
    4.错误代码

    遗憾的是,并不是在任何情况下都能够返回一个错误码.
    在Java中,如果某个方法不能够采用正常的途径完成它的任务,就可以通过另外一个路径退出方法.在这种情况下,方法并不返回任何值,而是抛出一个封装了错误信息的值.需要注意的是,这个方法将立刻退出,并不返回任何值.此外,调用这个方法的代码也将无法继续执行,而是,异常处理机制开始搜索能够处理这种异常状况的异常处理器.
    异常具有自己的语法和特定的继承结构.下面首先介绍一下语法,然后再给出有效地使用这种语言功能的技巧.

11.1.1  异常分类

    在Java程序设计语言中,异常对象都是派生于Throwable类的一个实例.如果Java中内置的异常类不能够满足需求,用户可以创建自己的异常类.
    需要注意的是, 所有的异常都是由Throwable继承而来.但在下一层立即分别为两个分支:Error和Exception .
    Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误.引用程序不应该抛出这种类型的对象.如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了.
    在设计Java程序时,需要关注Exception层次结构.这个层次结构又分解为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常.划分两个分支的规则是: 由程序错误导致的异常属于RuntimeException;而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常.
    派生于RuntimeException的异常包含下面几种情况:
    1.错误的类型转换
    2.数据访问越界
    3.访问空指针

    不是派生于RuntimeException的异常包括:
    1.试图在文件尾部后面读取数据
    2.试图打开一个不存在的文件
    3.试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在.

    "如果出现RuntimeException异常,那么就一定是你的问题"是一条相当有道理的规则.应该通过检测数组下标是否越界来避免ArrayIndexOutOfBoundsException异常;应该通过在使用变量之前检测是否为空来杜绝NullPointerException异常的发生.
    Java语言将派生于Error类或RuntimeException类的所有异常称为未检查异常,所有其他的异常称为已检查异常.
    注释:如果熟悉标准C++类库中的异常层次结构,就一定会感到困惑.C++有两个基本的异常类,一个是runtime_error;另一个是logic_error . logic_error类相当于Java中的RuntimeException,它表示程序中的逻辑错误;runtime_error是所有由于不可测的原因所引发的基类,它相当于Java中的非RuntimeException异常.

11.1.2  声明已检查异常

    如果遇到了无法处理的情况,那么Java方法可以抛出一个异常.这个道理很简单:一个方法不仅需要告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误.
    方法应该在其首部声明所有可能抛出的异常.这样可以从首部反映出这个方法可能抛出哪类已检查异常.
    需要记住在遇到下面4种情况下应该抛出异常:
    1.调用一个抛出已检查异常的方法.
    2.程序运行过程中发现错误,并且利用 throw 语句抛出一个已检查异常.
    3.程序出现错误.
    4.Java虚拟机和运行时库出现的内部错误.
    对那些可能被他人使用的Java方法,应该根据异常规范,在方法的首部声明这个方法可能抛出的异常.
class MyAnimation
{
    ...
    public Image loadImage(String s) throws IDException
    {
        ...
    }
}
    如果一个方法有可能出现多个已检查异常,那么就必须在方法的首部列出所有的异常类.每个异常类之间用逗号隔开.如下面这个例子所示:
class MyAnimation
{
    ...
    public Image loadImage(String s) throws FileNotFoundException, EOFException
    {
        ...
    }
}

11.1.3  如何抛出异常

    假如在程序代码中发生了糟糕的事情需要抛出异常,则
    1.找到一个合适的异常类
    2.创建这个类的一个对象
    3.将对象抛出
    注释:在C++与Java中,抛出异常的过程基本相同,只有一点微笑的差别.在Java中,只能抛出Throwable子类的对象,而在C++中,却可以抛出任何类型的值.

11.1.4  创建异常类

    创建新的异常类需要做的只是定义一个派生于Exception的类,或者派生于Exception子类的类.习惯上,定义的类应该包括两个构造器,一个是默认的构造器;另一个是带有详细描述信息的构造器.
class FileFormatException extends IOException
{
    public FileFormatException(){}
    public FileFormatException(String gripe)
    {
        super(gripe);
    }
}
    现在就可以抛出自定义的异常类型了.
String readData(BufferedReader in) throws FileFormatException
{
    ...
    while(...)
    {
        if (ch == -1)
        {
            if (n < len)
                throw new FileFormatException();
        }
        ...
    }
    return s;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值