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. 不要用异常处理来处理所有的出错