介绍
无论是使用文件 IO 流,还是网络 Socket 流,都免不了调用 close() 将流关闭。如果需要操作的流过多,就会导致混乱。一旦忘记将关闭方法放到 finally 中,很有可能出现流未被关闭,占用大量内存空间的问题。在try-with-resources
结构中会自动调用AutoCloseable
实现类的close()
方法,简化了流程,提高了代码效率。
Demo
try-catch-finally 与 try-with-resource
- try-catch-finally
AC ac = null;
AC2 ac2 = null;
try {
ac = new AC();
ac2 = new AC2();
} catch (Exception e) {
} finally {
ac.close();
ac2.close();
}
- try-with-resource
try (AC ac = new AC();
AC2 ac2 = new AC2()) {
sout("done~");
}
try-with-resource
语法的目的是提高Java开发人员的效率,使得他们不需要在编写代码时考虑资源释放问题,大多数的这类"清理"问题是由于异常发生时清理方法没有被调用产生。
测试
准备工作
AC.java
public class AC implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Program has been closed pretended.");
}
//默认静态方法,在被实例化时执行
static {
System.out.println("Program running.");
}
}
AC2.java
public class AC2 implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("Program 2 has been closed pretended.");
}
static {
System.out.println("Program 2 running.");
}
}
Main1.java
public class Main {
public static void main(String[] args) {
try (AC ac = new AC();
AC2 ac2 = new AC2()) {
//这里假装执行了有用的代码
Thread.sleep(2000);
} catch (Exception e) {
System.out.println("error~");
}
System.out.println("end~");
}
}
Main2.java
package autocloseable;
public class Main2 {
public static void main(String[] args) {
AC ac = new AC();
AC2 ac2 = new AC2();
try {
System.out.println("done~");
} catch (Exception e) {
System.err.println("error~");
} finally {
// 显示调用
// try {
// ac.close();
// ac2.close();
// } catch (Exception ex) {
// ex.printStackTrace();
// }
}
}
}
测试结果
Main1.java
Program running.
Program 2 running.
Program 2 has been closed pretended.
Program has been closed pretended.
end~
Main2.java
Program running.
Program 2 running.
done~
// 以下显示调用才会触发
Program has been closed pretended.
Program 2 has been closed pretended.
通过上述的测试对比,我们知道,AutoCloseable#close()
方法在try-with-resource
结构块结束的时候自动调用,方法调用完成之后,再继续向下执行。如果是try-catch-finally
结构块,则需要在finally
接口中显示调用close()
方法。
总结
- 资源必须是AutoCloseable的子类型,如果不是的话会得到一个编译期错误。
- 资源都是隐式final的,也就是说即便没有使用final,这些资源也都是final的。如果尝试为资源变量赋值会得到一个编译期错误。
- 资源关闭的顺序与定义的顺序正好相反。如上述的
ac, ac2
。这么做可以构建嵌套的流,然后从外向内关闭流,这要比按顺序关闭更好(也就是说,可以在底层的流关闭前先清空缓存)。