异常使得我们能将每件事都当做一个事务进行考虑,也可以看作是内建的恢复系统。
异常对象也在堆上创建,有两个构造器,一个是默认,另一个是接受字符串为参数以便放入相关信息的构造器: throw new NullPointerException("t = null");
创建完对象后,引用将传递给 throw。异常对象中仅有的信息就是异常类型,上一层环境通过获得这些信息来决定如何处理异常对象。
主流语言都是使用异常处理中的“终止模型”,捕获到异常马上中断执行。恢复模型虽然支持不断自动尝试解决问题,但是容易导致代码耦合问题。
将错误写入 System.err 发送给标准错误流比 System.out 好,因为 System.out 可能会被重定向。e.printStackTrace() 会将错误信息输出至标准错误流。
printStackTrace() 方法提供的信息可以通过 getStackTrace() 方法直接访问,该方法将返回一个由栈轨迹中的元素构成的数组,其中每一个元素代表栈中的一帧。0是栈顶元素,并且是调用序列中的最后一个方法调用;最后一个元素和栈底是第一个被调用的方法。
可以通过
catch(Exception e)
{
throw e;
}
重新抛出异常,将异常交给上一级处理,同一个 try 块的后续 catch 子句将被忽略,并且异常对象的所有信息都得以保持。重新抛出后,如果想要得到异常的新发生地,可以调用 fillInStackTrace() 方法返回一个 Throwable 对象,其通过将当前调用栈信息填入原来的异常对象而建立。
在 Throwable 子类的构造器当中,都可以接受一个 cause 对象作为参数,以这个 cause 表示原始异常。只有三种基本类型异常类提供了带 cause 参数的构造器。Error、Exception 以及 RuntimeException。要将其它类型异常连接起来,使用 initCause() 方法。
当需要将内存之外的的资源恢复到初始状态时需要使用 finally 子句,而且无论有多少个 return 语句在前面,finally 总是会执行。但是如果在 finally 块中写入 return 语句,则会导致异常无法正常抛出。
覆盖方法时,只能抛出在基类方法的异常说明里列出的异常。然而该限制对于构造器不起作用,但是派生类构造器的异常说明必须包含基类构造器的异常说明且不能捕获基类构造器抛出的异常。
抛出异常时,会自动匹配书写顺序最近的处理语句。查找时不要求异常和处理程序完全匹配,派生类对象也可以匹配基类的处理语句。