[think in java]第12章 通过异常处理错误

异常处理是java中唯一正式的错误报告机制。并且通过编译器强行执行。


异常参数

抛出异常与方法正常返回值的区别:异常返回的“地点”与普通方法调用返回的"地点"完全不同。(异常将在一个恰当的异常处理程序中得到解决,他的位置可能离异常被抛出的地方很远,也可能会跨越方法调用栈的许多层次。)

对异常来说,最重要的部分就是类名。


捕获异常

异常处理理论上有两种模型:终止模型和恢复模型。java支持终止模型。对于恢复模型,由于其紧耦合程度太高,所以可以用行不大。

在异常处理程序中,Throwable类声明(Exception即从此类继承)的printStackTrace()方法,默认将信息输出到标准错误流,也可通过加参数改变输出流。如:e.printStackTrace(system.out); 信息被输出到标准输出流。


异常与记录日志

随时记录程序的日志是个好习惯。java中可以用静态的Logger.getLogger()方法获得日志记录的对象。


重新抛出异常

重抛异常会把异常抛给上一级环境中的异常处理程序,同一个try块的后续catch子句将被忽略。如果只是把当前异常对象重新抛出,那么printStackTrace()方法显示的是原来异常抛出点的调用栈信息,而非重新抛出点的信息。想要更新这个信息,可以调用fillInStackTrace()方法,这将返回一个Throwable对象。如:

throw (Exception)e.fillInStackTrace();
有可能在异常捕获之后抛出另一种异常。这么做得到的效果类似使用fillInStackTrace().有关原来异常发生点的信息会丢失。剩下的是新的抛出点信息。


异常链

在捕获一个异常后抛出另一个异常,并且希望把原始异常的信息保存下来,这被称为异常链。所有的Throwable的子类在构造器中都可以接受一个cause对象作为参数。这个cause就用来表示原始异常,这样就可以把原始异常传递给新的异常,是的即使在当前位置创建并抛出了新的异常,也能通过这个异常链追踪到异常的最初发生位置。

在Throwable的子类中,只有三个基本的异常类提供了带cause参数的构造器,他们是Error(java虚拟机报告系统错误),Exception,以及RuntimeException。如果要把其他类型的异常链接起来,应该使用initCause()方法而不是构造器。


java标准异常

Throwable类对象可以分为两种类型:Error用来表示编译时和系统错误;Exception是可以被抛出的基本类型,在java类库/用户方法以及运行时故障中都可能抛出Exception。所以我们关系的基类型通常是Exception。

请务必记住:只能在代码中忽略RuntimeException(及其子类)类型的异常,其他类型异常的处理都是由编译器强制实施的。究其原因,RuntimeException是编程错误:

  1. 无法预料的错误。比如在你控制范围内引入null引用。
  2. 应该在代码中检查的错误。如数组越界访问。、

缺憾:异常丢失

如下例子所示:

public void main(String [] args)
{
	try{
		throw new RuntimeException();
	}finally{
		return;
	}
}
该方法直接通过finally将异常淹没了。造成了异常丢失。


异常的限制

当覆盖方法的时候,只能抛出在基类方法的异常说明里列出的那些异常。这意味着,当基类使用的代码应用到其派生类对象时,一样能够工作

异常限制对构造器不起作用。子类构造器可以抛出任何异常,而不必理会基类构造器所抛出的异常。然而,积累的构造器必须以这样或那样的方式调用(被自动调用),派生类构造器必须包含基类构造器的异常说明

派生类构造器不能捕获基类构造器抛出的异常

尽管在继承过程中,编译器会对异常说明做强制要求,但异常说明本身并不属于方法类型的一部分。方法类型是由方法的名字和参数的类型组成的。因此,不能基于异常说明来重载方法。


郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。