首页 > 代码库 > 异常中的陷阱

异常中的陷阱

正确关闭资源的方式

①使用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;        }    }}

打印结果为:

image_thumb[7]

我们来看看反编译后的代码:

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;  }}

image_thumb[10]

image_thumb[11]

image_thumb[12]

image_thumb[13]

为什么没有放在finally块中呢?因为,从代码块看,count+=2;处于前一个return和后一个return之后,即,当前一个return不起作用的情况下才会执行这个语句。前一个return不起作用的情况只有try中出现了异常,所以count+=2放到了catch块中,而finally块每次都会被执行,放在这里没有任何意义。

image_thumb[14]

因为finally总会被执行,而这里函数已经返回,绝对不会再放后面执行了,所以count是不可达的。出现编译错误。

image_thumb[15]

如果有finally语句,则try中的return 语句会把要返回的值先保存了一份,然后去执行finally语句,finally语句执行完毕之后再返回之前try语句块中保存的那个值,如果try中return的是基本类型的,finally里对变量的改动将不起效果,如果return的是引用类型的,那改动了对象中的值就可以起效果。

image_thumb[16]

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异常,如:

image_thumb[17]

只要愿意,程序总可以使用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

异常中的陷阱