一、使用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语句,这个修改也会作用于返回值上。
2.请勿在try代码块中调用return、break或continue语句。万一无法避免,一定要确保finally的存在不会改变函数的返回值。
3.函数返回值有两种类型:值类型与对象引用。对于对象引用,要特别小心,如果在finally代码块中对函数返回的对象成员属性进行了修改,即使不在finally块中显式调用return语句,这个修改也会作用于返回值上。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
补充:不要在循环里写try/catch,要将循环写在try/catch块中。
在启用JIT编译器的情形下两种方式生成的bytecode是几乎相同的,执行时间并没有什么不同。但是一旦将JVM的JIT关闭后,两者的bytecode差异很大,第二种方式执行效率会更高些。