Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1740593
  • 博文数量: 438
  • 博客积分: 9799
  • 博客等级: 中将
  • 技术积分: 6092
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-25 17:25
文章分类

全部博文(438)

文章存档

2019年(1)

2013年(8)

2012年(429)

分类: Java

2012-03-25 22:06:39

Java中可以通过throw抛出所有继承Throwable的类。任何抛出的异常(RuntimeException除外)被编译器强制需要catch,如果不catch会出现编译错误。


  1. void makeExcetion()
  2. {
  3.     // throw new MyException(); // error: this exception must be handled.
  4. }

如果需要把异常抛到方法外,则需要在方法定义中声明该异常
  1. void makeException() throws MyException
  2. {
  3.     throw new MyException();
  4. }

这样编译器才会让你通过,但是所有调用了这个方法的地方必须catch这个被声明的异常,否则编译不通过,(当然也可以通过上述声明异常的方式把异常抛到更外层)。相比之下,C++的异常声明更像一个提示,不带有强制性质。


Throwable分为两种类型:ErrorException。Error用来表示编译时和系统错误,所以我们一般不用关心。Exception类有一个方法printStackTrace可以打印出异常抛出点的调用栈,另一个函数fillStackTrace可以在catch后更新调用栈信息再抛出。

RuntimeException是Exeption的子类,用来表示运行时发现的编程错误,比如访问空指针(NullPointerException)和数组越界(ArrayIndexOfBound***ception)。这种类型的异常是唯一不被编译器强制需要捕获的。如果一个RuntimeException抛出后没有被catch,程序会退出并调用printStackTrace方法。

使用finally块可以保证不管是否有异常发生,该块的代码都会被运行:


  1. try
  2. {
  3.     // dosomething
  4. }
  5. catch (Exception e)
  6. {
  7. }
  8. finally
  9. {
  10.     // always be executed. Usually dispose.
  11. }

finally也可以用来保证有多个return点的函数可以执行必要的清理工作,这也弥补了没有析构的不足。


有时候你可能需要把一些异常串成一个异常链。Exception.initCause可以支持这个需求:


  1. class LevelOneException extends Exception {}
  2. class LevelTwoException extends Exception {}

  3. class ExceptionMaker {
  4.     void makeLevelOne() throws LevelOneException
  5.     {
  6.         throw new LevelOneException();
  7.     }
  8.     void makeLevelTwo() throws LevelTwoException
  9.     {
  10.         try {
  11.             makeLevelOne();
  12.         }
  13.         catch (LevelOneException loe)
  14.         {
  15.             LevelTwoException lte = new LevelTwoException();
  16.             lte.initCause(loe); // combine the exceptions
  17.             throw lte;
  18.         }
  19.     }
  20.     void Test()
  21.     {
  22.         try {
  23.             makeLevelTwo();
  24.         }
  25.         catch (LevelTwoException lte)
  26.         {
  27.             Throwable t = lte.getCause(); // get the previous exception in the link
  28.         }
  29.     }
  30. }


在C++里,当一个异常没有被Catch的情况下,再抛出一个新的异常,比如析构函数里的异常,这个程序基本就over了。但在Java中,这种情况会导致旧的异常丢失,新的异常被传递出去:


  1. void loseException() {
  2.     try {
  3.         try {
  4.             throw new LevelOneException();
  5.         } finally {
  6.             throw new LevelTwoException();
  7.         }
  8.     } catch (LevelTwoException lte) {
  9.         lte.printStackTrace();
  10.     }
  11. }

这应该算是Java的一个缺陷吧。


在覆写父类方法时,子类方法中的异常声明必须是父类声明的异常的子集。就是说子类的方法只能抛出比父类更少的异常,而不能抛出父类不会抛出的异常。

阅读(808) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~