而不是我们期望得到的数据库异常。这是因为这里的con是null的关系,在finally语句中抛出了NullPointerException,在finally块中增加对con是否为null的判断可以避免产生这种情况。
丢失的异常
请看下面的代码:
public void method2() { try { …… method1(); //method1进行了数据库操作 } catch(SQLException e) { …… throw new MyException("发生了数据库异常:"+e.getMessage); } } public void method3() { try { method2(); } catch(MyException e) { e.printStackTrace(); …… } } |
上面method2的代码中,try块捕获method1抛出的数据库异常SQLException后,抛出了新的自定义异常MyException。这段代码是否并没有什么问题,但看一下控制台的输出:
MyException:发生了数据库异常:对象名称'MyTable' 无效。
at MyClass.method2(MyClass.java:232)
at MyClass.method3(MyClass.java:255)
原始异常SQLException的信息丢失了,这里只能看到method2里面定义的MyException的堆栈情况;而method1中发生的数据库异常的堆栈则看不到,如何排错呢,只有在method1的代码行中一行行去寻找数据库操作语句了。
JDK的开发者们也意识到了这个情况,在JDK1.4.1中,Throwable类增加了两个构造方法,public Throwable(Throwable cause)和public Throwable(String message,Throwable cause),在构造函数中传入的原始异常堆栈信息将会在printStackTrace方法中打印出来。但对于还在使用JDK1.3的程序员,就只能自己实现打印原始异常堆栈信息的功能了。实现过程也很简单,只需要在自定义的异常类中增加一个原始异常字段,在构造函数中传入原始异常,然后重载printStackTrace方法,首先调用类中保存的原始异常的printStackTrace方法,然后再调用super.printStackTrace方法就可以打印出原始异常信息了。可以这样定义前面代码中出现的MyException类:
import java.io.PrintStream; import java.io.PrintWriter; public class MyException extends Exception { private static final long serialVersionUID = 1L; //原始异常 private Throwable cause; //构造函数 public MyException(Throwable cause) { this.cause = cause; } public MyException(String s,Throwable cause) { super(s); this.cause = cause; } //重载printStackTrace方法,打印出原始异常堆栈信息 public void printStackTrace() { if (cause != null) { cause.printStackTrace(); } super.printStackTrace(); } public void printStackTrace(PrintStream s) { if (cause != null) { cause.printStackTrace(s); } super.printStackTrace(s); } public void printStackTrace(PrintWriter s) { if (cause != null) { cause.printStackTrace(s); } super.printStackTrace(s); } } |