一、所有异常都是由Throwable继承而来,但在下一层立即分解为两个分支:Error和Exception。
Error类层次结构描述了Java运行时系统的内部错误和资源耗尽错误。如果出现了这种错误,除了通告给用户,并尽力使程序安全地终止之外,再也无能为力了。
Exception层次结构又分解为两个分支:一个分支派生于RuntimeException;另一个分支包含其他异常。
划分这个分支的规则是:由程序错误导致的异常属于RuntimeException;而程序本身没错,但由于I/O错误这类问题导致的异常属于Checked Exception。
派生于Error类或RuntimeException类的所有异常称为未检查(unchecked)异常;所有其他异常,称为(checked)异常。
二、派生于RuntimeException的异常包含下面几种情况:
1、错误的类型转换
2、数组访问越界
3、访问空指针
注:如果出现RuntimeException,那么一定就是程序编写有误。
CheckedException包含下面几种情况:
1、试图在文件尾部后面读取数据
2、试图打开一个错误格式的URL
3、试图根据给定的字符串查找Class对象,而这个字符串表示的类并不存在
注:是否出现这些异常与程序无关,只取决于具体的环境;
编译器必须为所有的已检查异常(CheckedException)提供异常处理器。
三、如果在子类中覆盖了超类的一个方法,子类方法中声明的已检查异常不能超过超类方法中声明的异常范围(也就是说,子类方法中抛出的异常范围更小,或者根本不抛出任何异常)
延伸:如果类中的一个方法声明将会抛出一个异常,而这个异常是某个特定类的实例时,则这个方法就有可能抛出一个这个类的异常,或者这个类的任意一个子类的异常。
在Java中,没有throws说明符的方法将不能抛出任何已检查异常。
四、通常,应该捕获那些知道如何处理的异常,而将那些不知道怎样处理的异常传递出去。
在catch子句中可以抛出一个异常,这样做的目的是改变异常的类型。
五、包装技术:将原始异常设置为新异常的“诱饵”
try{
access the database
}catch(SQLException e){
Thorwable se = new ServletException("database error")
se.initCause(e);
throw se;
}
当捕获到异常时,就可以使用下面这条语句重新得到原始异常:
Throwable e = se.getCause();
使用这种包装技术,可以让用户抛出子系统中高级异常,而不会丢失原始异常的细节。
六、假设利用return语句从try语句块中退出。在方法返回前,finally字句的内容将被执行。如果finally子句中也有一个return语句,这个返回值将会覆盖原始的返回值。
七、强烈建议独立使用try/catch和try/finally语句块,这样可以提高代码的清晰度。
InputStream in = ...;
try{
try{
code that might throw exception
}finally{
in.close();
}
}catch(IOException e){
e.printStaceTrace();
}
八、构造一个Throwable对象,并调用getStackTrace方法获得一个StackTraceElement对象的数组。分析数组元素,可以获得构造这个对象时调用堆栈的跟踪(当前线程)
Throwable t = new Throwable();
for(StackTraceElement s : t.getStaceTrace())
System.out.println(s);