1.在Java程序设计语言中,异常对象都是派生于Throwable类的一个实例。在Throwable的下一层分解为两个分支:Error和Exception。
Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。如果出现了这样的内部错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了。这种情况很少出现。
设计Java程序时,需要关注Exception层次结构。这个层次结构又分解为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。划分两个分支的规则是:由程序错误导致的异常属于RuntimeException;而程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常。
派生于RuntimeException的异常包含以下几个情况:
(1)错误的类型转换
(2)数组访问越界
(3)访问空指针
不是派生于RuntimeException的异常包括:
(1)试图在文件尾部读取数据
(2)试图打开一个错误格式的URL
(3)试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
如果出现RuntimeException异常,那么就一定是程序员的问题。
Java语言规范将派生于Error类或RunTimeException类的所有异常称为未检查(unchecked)异常,所有其他的异常称为已检查(checked)异常。
一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。如果方法没有声明所有可能发生的已检查异常,编译器就会给出一个错误消息。
2.如果在子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能超过超类方法中声明的异常范围。特别需要说明的是,如果超类方法没用抛出任何已检查异常,子类也不能抛出任何已检查异常。
3.在C++和Java中,抛出异常的过程基本相同,只有一点微小的差别。在Java中只能抛出Throwable子类的对象,而在C++中,却可以抛出任何类型的值。
4.为了让用户抛出子系统中的高级异常,而不会丢失原始异常的细节,可以使用如下包装技术:
try
{
XXXXXX
}
catch(Exception e)
{
Throwable mye = new MyException("my info");
mye.initCause(e);
throw mye;
}
当捕获到异常时,就可以使用下面这条语句重新得到原始异常:
Throwable e = mye.getCause();
5.在JavaSE5.0中,增加了一个静态的Thread.getAllStackTrace方法,它可以产生所有线程的堆栈跟踪。方法的具体实现方式如下:
Map<Thread,StackTraceElement[]> map = Thread.getAllStackTraces();
for(Thread t:map.keySet())
{
StackElement[] frames = map.get(t);
分析 frames
}
6.使用断言的建议:
断言失败是致命的,不可恢复的错误
断言检查只用于开发和测试阶段
因此,不应该使用断言向程序的其他部分通告发生了可恢复性的错误,或者,不应该作为程序向用户通告问题的手段。断言只应该用于在测试阶段确定程序内部的错误位置。