Create by westfallon on 8/13
异常
处理错误
- 如果由于出现错误而使得某些操作没有完成,程序应该:
- 返回到一种安全状态,并能够让用户执行一些其他命令
- 允许用户保存所有操作的结果,并以适当的方式终止程序
- 异常处理的任务就是将控制权从错误产生的地方转移给能够处理这种情况的错误处理器
异常分类
- 在Java中,异常对象都是派生于Throwable类的一个实例,在下一层被分为Error和Exception两类
- Error类描述了Java运行时系统内部错误和资源耗尽错误
- Exception类又分解为两个分支,一个分支派生于RuntimeException,另一类包含其他异常,划分规则是:由程序错误导致的异常属于RuntimeException,而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常
- 派生于RuntimeException的异常包括以下几种情况:
- 错误的类型转换
- 数组访问越界
- 访问空指针
- 其他异常包括:
- 试图在文件尾部后面读取数据
- 试图打开一个不存在的文件
- 试图根据给定的字符查找Class文件,而这个字符串表示的类根本不存在
- 派生于Error类或RuntimeException类的所有异常被称为未检查(unchecked)异常,所有其他的异常被称为已检查(checked)异常
声明已检查异常
- 一个方法不仅应该告诉编译器将要返回什么值,还要告诉编译器有可能发生什么错误
- 在遇到以下四种情况时应该抛出异常:
- 调用一个抛出已检查异常的方法
- 程序运行过程中出现错误
- 程序出现错误
- Java虚拟机和运行库出现的内部错误
- 一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)
- 如果子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能比超类方法中声明的异常更通用,也就是说,子类方法中可以抛出更特定的异常,或者根本不抛出异常。如果超类方法中没有抛出任何异常,子类也不能抛出任何已检查异常
如何抛出异常
- 找到一个合适的异常类
- 创建这个类的一个对象
- 将对象抛出
捕获异常
- 通常,应该捕获那些知道如何处理的异常,而将那些不知道怎样处理的异常继续传递
- 如果想传递一个异常,就必须在方法的首部添加一个throws说明符,以便告诉调用者这个方法可能会抛出异常
- 在catch语句中可以抛出一个异常,这样做的目的是改变异常的类型
- 建议独立使用try/catch和try/finally语句块
内层的语句块只有一个职责就是确保关闭输入流,外层的语句块也只有一个职责就是确保报告出现的错误InputStream in = ...; try{ try{ code; } finally{ in.close(); } } catch(IOException e){ code; }
带资源的try语句
try (Resource res = ...){
code;
}
分析堆栈跟踪元素
- 堆栈跟踪(stack trace)是一个方法调用过程的列表,包含了程序执行过程中方法调用的特定位置
使用异常机制的技巧
- 异常处理不能代替简单的测试
- 不要过分的细化异常
- 利用异常层次结构
- 不要压制异常
- 在检测错误时要细化异常类型
- 不要羞于传递异常
断言
- 断言机制允许在测试期间向代码中插入一些检查语句,当代码发布时,这些插入的检测语句会被自动地移走