首页 > 代码库 > 异常中的陷阱
异常中的陷阱
正确关闭资源的方式
①使用finally块来关闭物理资源。
②关闭物理资源时,首先保证引用资源的变量不为null
③每个物理资源时都应该使用单独的try-catch块来关闭资源,保证关闭资源时引发的异常不会影响其他资源的关闭。
finally的陷阱
System.exit(0);
在try中使用了System.exit(0);语句,将停止当前线程和所有其他当场死亡的线程。catch和finally块都不会被执行。因为线程都立即死亡了,怎么会执行下面的东西呢?
那么当出现System.exit(0);语句后,我们怎么来清理物理资源呢?
→将关闭资源的操作注册为关闭钩子。(JVM在退出之前,这些关闭钩子会被调用,从而保证物理资源被正常关闭)。
public class test { public static void main(String[] args) throws Exception { final FileOutputStream fos; fos=new FileOutputStream("D:\\a.bin"); System.out.println("程序打开物理资源"); //为系统注册关闭钩子 Runtime.getRuntime().addShutdownHook(new Thread(){ public void run(){ //使用关闭钩子来关闭资源 if(fos!=null){ try { fos.close(); } catch (Exception e) { e.printStackTrace(); } } System.out.println("程序关闭了物理资源"); } }); //退出程序 System.exit(0); }}
finally块和try中的return、throw
public class test { public static void main(String[] args) throws Exception { int a=test1(); System.out.println(a); } public static int test1(){ int count=5; try { return count+=5; } catch (Exception e) { // TODO: handle exception }finally{ System.out.println("finally块被执行"); return count+=10; } }}
打印结果为:
我们来看看反编译后的代码:
public class test { public static void main(String[] args) throws Exception { int a = test1(); System.out.println(a); } public static int test1() { int count = 5; try { count += 5; } catch (Exception localException) {}finally { System.out.println("finally块被执行"); } count += 10;return count; }}
为什么没有放在finally块中呢?因为,从代码块看,count+=2;处于前一个return和后一个return之后,即,当前一个return不起作用的情况下才会执行这个语句。前一个return不起作用的情况只有try中出现了异常,所以count+=2放到了catch块中,而finally块每次都会被执行,放在这里没有任何意义。
因为finally总会被执行,而这里函数已经返回,绝对不会再放后面执行了,所以count是不可达的。出现编译错误。
如果有finally语句,则try中的return 语句会把要返回的值先保存了一份,然后去执行finally语句,finally语句执行完毕之后再返回之前try语句块中保存的那个值,如果try中return的是基本类型的,finally里对变量的改动将不起效果,如果return的是引用类型的,那改动了对象中的值就可以起效果。
try中的return被短路了。
当程序执行try块、catch块时,遇到throw语句时,throw语句会导致该方法立即结束,系统执行throw语句并不会立即抛出异常,而是去寻找该异常处理流程中是否包含finally块。如果没有finally块,程序立即抛出异常;如果有finally块,系统立即开始执行finally块,只有当finally块执行完后,系统才会再次跳回来抛出异常。如果finally块中使用了return语句来结束方法,系统不会跳回去执行try块、catch块去抛出异常。
只能catch try中可能抛出的异常
try中有可能抛出什么异常,后面的catch中才能捕获什么异常,否则会出现编译错误。但是Exception是个例外,即无论try块是什么代码,catch(Exception e)总是正确的。
RuntimeException类及其子类的实例被称为Runtime异常,不是RuntimeException类的及其子类的异常实例被称为Checked异常,如:
只要愿意,程序总可以使用catch(XxxException ex)来捕获运行时异常,它比较灵活,无需显示声明抛出,只要程序需要,即可在任何又需要的地方使用try...catch块来捕获runtime异常。但是catch如果捕获一个Checked异常,那么该catch对象的try必须能抛出该类或其子类的异常。
本文链接:http://www.cnblogs.com/yaoyinglong/p/Java%E5%BC%82%E5%B8%B8%E4%B8%AD%E7%9A%84%E9%99%B7%E9%98%B1.html
异常中的陷阱