finally

来源:互联网 发布:mac os sierra升级 编辑:程序博客网 时间:2024/05/21 22:52

一、使用finally避免内存泄漏

由于Java支持垃圾回收机制,为此,如果函数正常结束或异常而被迫退出,该函数所创建的所有对象会被自动回收,但是对于Socket或File资源必须要执行清理操作,以便资源回收。如果不对这些资源进行回收,那么就会出现内存泄漏。

public void reclaimResource() throws IOException{    ServerSocket server = new ServerSocket(5566);    Socket socket = null;    try{socket = server.accept();//业务代码.....    }finally{if(null != socket)    socket.close();//回收资源 if(null != server)    server.close();//回收资源}    }}

二、不要在finally块中处理返回值


public class FinallyTest {//把一个字符串转换为整数public static int getNumber(String str)       throws NumberFormatException {try {    int number = Integer.parseInt(str);    return number; //1} catch (NumberFormatException ex) {    throw ex;  //2} finally {            return -1; //3}    }//测试客户端public static void main(String[] args) {try {    int ret1 = getNumber("abc"); //4    int ret2 = getNumber("123"); //5    System.out.println("ret1=" + ret1 + ";ret2=" + ret2);} catch (Exception ex) {    ex.printStackTrace();}    }

答案揭晓: ret1=-1;ret2=-1


问题1:覆盖了try子句中的返回值


当执行代码2中的//4语句时,在getNumber函数中会产生一个NumberFormatException的异常,catch块在捕捉到该异常后直接抛出,之后的代码执行到了finally代码块,就会重置返回值为-1。

当执行代码2中的//5语句时,在getNumber函数中不会产生异常,会继续执行try代码块中的//1语句,但是此时函数并不会马上返回,之后的代码会执行到finally代码块,仍重置返回值为-1。


问题2:屏蔽了异常


当执行代码2中的//4语句时,明明抛出了异常,为什么在main函数中却捕捉不到了?

在异常代码块中,代码中加上try代码块就标志JVM运行到该语句时会有一个Throwable线程监视该方法运行,若出现异常,则交由异常逻辑处理,如代码2中就会登记当前的异常类型为NumberFormatException;接着执行器会执行finally代码块,会重新给方法运行状态赋值,按照如上finally的业务代码,也就是告诉调用者“该方法执行正确,没有产生异常,返回值为1”。于是,异常就这样消失了。


-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
思考:输出的值是什么?

public class FinallyTest {    static class Color {private String name;public Color(String nm) {    this.name = nm;}public String getName() {    return this.name;}public void setName(String nm) {    this.name = nm;}    }    public static Color getColor() {Color color = new Color("Red");try {    return color;} catch (Exception ex) {} finally {    color.setName("Black"); }    return color;    }    // 测试客户端    public static void main(String[] args) {Color color = getColor();System.out.println(color.getName());    }}

答案是:Black


*因为前面提到try块并没有直接返回,而是执行了finally块中的语句,然后再返回。


1.按照我们程序员的惯性认知:当遇到return语句的时候,执行函数会立刻返回。但是,在Java语言中,如果存在finally就会有例外。除了return语句,try代码块中的break或continue语句也可能使控制权进入finally代码块。
2.请勿在try代码块中调用return、break或continue语句。万一无法避免,一定要确保finally的存在不会改变函数的返回值。
3.函数返回值有两种类型:值类型与对象引用。对于对象引用,要特别小心,如果在finally代码块中对函数返回的对象成员属性进行了修改,即使不在finally块中显式调用return语句,这个修改也会作用于返回值上。

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


补充:不要在循环里写try/catch,要将循环写在try/catch块中。

在启用JIT编译器的情形下两种方式生成的bytecode是几乎相同的,执行时间并没有什么不同。但是一旦将JVM的JIT关闭后,两者的bytecode差异很大,第二种方式执行效率会更高些。

原创粉丝点击