Practical JAVA (四)异常处理

Practice 16~27

异常控制流(exceptional control flow)机制:

 

 

 1 try{
 2   <block>    
 3 }
 4 catch(<ExceptionClass> e){
 5   <block>  
 6     throw e; //若不能处理该异常,则抛出
 7 }
 8 finally{
 9   <block>  
10 }

 

若在try段抛出异常,先跳过try段内异常后面的语句,执行catch段,再执行finally段,否则,执行完try段,直接处理finally段

若catch段中再次抛出异常,则抛出后依旧执行finally段

如果try里面有return语句被执行,还是会在之后执行finally段。所以在try里使用return要谨慎,最好不要用。

 

 

 

处理多个异常,防止被最后一个异常掩盖

 

 

一个函数当中,只有最后抛出的异常才会被调用它的函数接收

比如

class Hidden{
  public static void main(String args[])
  Hidden h = new Hidden();
  try{
    h.foo();
  }  
  catch (Exception e){
    System.out.println("In main, caught exception: " + e.getMessage());
  }
  public void foo() throws Exception{
    try{
      throw new Exception("First Exception");
    }
    catch (Exception e){
      throw new Exception("Second Exception");
    }
    finally{
      throw new Exception("Third Exception");
    }
  }
}

运行结果为:

In main, caught exception: Third Exception

再比如,在读文件的过程中:

class Hidden{
  public static void main(String args[]) {
    Hidden h = new Hidden();
    try {
      h.readFile();
    }
    catch(FileNotFoundException fne){
      //
    }
    catch(IOException ioe){
      //
    }
  } 
  public void readFile() throw FileNotFoundException, IOException{
    BufferedReader br1 = null;
    BufferedReader br2 = null;
    FileReader fr = null;
    try{
      fr = new FileReader("data1.fil");
      br1 = new BufferedReader(fr);
      int i = br1.read();
      //
      fr = new FileReader("data2.fil");
      br2 = new BufferedReader(fr);
      i = br2.read();
      //
    }
    finally {
      if(br1!=null) br1.close();
      if(br2!=null) br2.close();
    }
  }
}

调用FileReader函数可能产生FileNotFoundException,调用BufferedReader函数,close函数,可能产生IOException

若文件在FileReader的时候产生FileNotFoundException,在close的时候又产生IOException,则真正导致程序出错的原因:文件打不开 会被掩盖

这个时候,要建一个stack来储存这些exception

代码懒得打了,直接截图

 三

较复杂的异常处理的原则:

 

考虑三个问题:异常发生的时候会如何?异常处理后会如何?复入这段代码会如何?

最后一个问题最难回答

可以参考database当中transaction的想法

 

四 

如何处理构造对象时产生的错误

 

构造对象没有返回值,因此很难判断构造对象是否成功。

避免这种情况的方法有:

方法一

双阶段建构(two-stage construction),将有可能产生错误的代码移出构造函数,组成可以返回错误码的函数

方法二

双阶段建构的另一种形式

使用一个internal flag,代表这个对象建构后的有效性

方法三

在构造函数中抛出异常

异常处理的一种方法是记录异常,一种是将异常写入自己设定的文件,一种是e.printStackTrace(System.err);这个函数提供被抛异常的消息,以及该异常的起源(以stack trace方式呈现),并将它们输出到标准错误串流(standard error stream)。

 

finally

关于异常处理的一些tips:

1. 在finally里关闭文件,socket等,避免资源泄露

2. 在函数旁边写上 throws <ExceptionClass>,方便调用它的函数进行异常处理

3.不要在循环中使用异常处理

4. 不要用异常处理代替流程控制

5. 不要用异常处理来处理所有的出错

posted @ 2016-01-09 20:16  Gryffin  阅读(163)  评论(0编辑  收藏  举报