No.8 异常捕捉的陷阱

1. 正确关闭资源

  • 开发中打开的一些物理资源,必须显示进行关闭。Java回收机制是内存管理的一部分,只能对堆内存回收,对程序中打开的物理资源无能为力。必须进行显式关闭资源

2. finally

  • 不论try块是正常结束,还是中途非正常退出,即使其包含return语句,finally块都会执行
  • 但是碰到System.exit(0)时呢?System.exit(0)将停止当前线程和所有其他当场死亡的线程。finally块不能使已经停止的线程继续执行,因此,其中的方法就得不到执行
  • 那么遇到System.exit(0)应该怎么关闭资源呢?
    • 注册关闭钩子,因为System.exit(0)被调用时,虚拟机退出前要执行清理工作:执行系统中注册的所有关闭钩子
      public class ExitHook {
          public static void main(String[] args) throws IOException {
              final FileOutputStream fos;
              fos = new FileOutputStream("a.bin");
              System.out.println("打开物理资源");
              
              Runtime.getRuntime().addShutdownHook(new Thread(){
                  public void run() {
                      if (fos != null) {
                          try {
                              fos.close();
                          } catch (IOException e) {
                              // TODO Auto-generated catch block
                              e.printStackTrace();
                          }
                      }
                      System.out.println("关闭了物理资源");
                  }
              });
              
              // 退出程序
              System.exit(0);
              
          }
      }
      View Code

       关闭钩子负责在程序退出时回收系统的资源

  • 只要Java虚拟机不退出,不管try块正常结束,还是遇到异常非正常退出,finally块总会获得执行机会
    • 当Java程序try、catch块中遇到了return语句时,并不会立即执行该语句,而是:去寻找异常处理流程中是否包含finally块,若无,方法执行return结束;若有,开始执行finally块,当finally块执行完后,调回去执行return语句结束,如果finally块中含有return语句,则直接在finally块中结束方法,不会再跳回去执行try块中的return语句
    • 当Java程序try、catch块中遇到了throw语句时,并不会立即执行该语句,抛出异常,而是:去寻找异常处理流程中是否包含finally块,若无,方法执行throw抛出异常;若有,开始执行finally块,当finally块执行完后,调回去执行throw抛出异常,如果finally块中含有return语句,则直接在finally块中结束方法,不会再跳回去执行try块中的throw抛出异常

3. catch块

  • 对Java的异常捕捉,每个try至少  需要 一个 catch或者finally块
  • 异常捕获时,先捕获小异常,再捕获大异常
  • 不要用异常来进行流程控制:难以阅读、运行速度慢。异常是为捕获异常而存在的,不能用其进行流程控制
  • 只可以捕获可能抛出的异常
    • 可以在任意想捕获异常的地方捕获RuntimeException异常、Exception异常,但是对于其他checked异常(Exception异常是个另类),只有当可能抛出该类异常时才能 捕获,否则编译错误
  • 实际修复
    • 方法知道怎么修复异常,try...catch
    • 方法不知道怎么修复,抛出
      • 在catch块中不进行修复又调用抛出异常的该方法,造成无线递归,StackOverflowError
      • 无论如何不要在finally块中调用可能引起异常的方法,这将导致该方法的异常不能被正常抛出,甚至StackOverflowError错误也不能终止程序,只能采用强行结束进程

4.继承得到的异常

  • 子类重写父类父类的方法,不能声明抛出比父类类型更多、范围更大的异常。也就是说只能抛出其子类、相同的、或者不抛出
  • 实现接口中的方法时抛出异常要求同上。当是实现多个接口时,多个接口若有相同的方法,在实现该方法时,抛出的异常只能是多个接口分别可以抛出的异常类型的交集,即必须满足每个接口的要求。(方法不抛出异常,肯定是其的一个交集)
posted @ 2017-01-11 11:53  郭天  阅读(200)  评论(0编辑  收藏  举报