一、在Java中为何要关闭流
GC运行的时间点是不确定的(因为是一条单独存在的线程),所以很多时候你不能直接控制什么时候发生GC。这个带来的问题有两点,一个是有时候你的内存不足需要立刻回收而GC并不会立刻运行;另外一个是因为GC运行期间会占用大量系统资源所以某些情况下你会希望把它推后,或者干脆关掉以便根据性能需求在合式的时候手动执行。
另外,GC只能回收内存。至于各种stream之类,他们下边一般还开启了各种其他的系统资源,比如文件,比如输入输出设备(键盘/屏幕等),等等。而这些设备第一是不能自动关闭(因为谁知道你程序要用它到什么时候啊),另一个系统内数量有限(比如键盘/屏幕同一时间只有一个)。最后,文件和数据库连接之类的东西还存在读写锁定的问题。这些都导致用户必须手动处理这些资源的开启和关闭。
这年头自动挡汽车都那么好了还不是有那么多人喜欢手挡,一样的。
流不关资源占着内存,你一个小的程序感觉不出来,要是好多流都不关,就会导致死机,内存泄流!建议培养良好的编码意识,一个小的程序也要吧流关了。
二、TryWithResources
这个不妨直接来看Oracle公司所提供的JavaDoc好了,毕竟可以这么说,这只是从Java SE 7开始提供的一个语法糖。 https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html
官方描述:
The try
-with-resources statement is a try
statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try
-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable
, which includes all objects which implement java.io.Closeable
, can be used as a resource.
解释一下:
使用try
语句来声明一个或多个资源,这里的资源都是在程序执行完毕之后必须要被关闭的对象。TryWithResources声明确保了每一个资源最终都会在程序运行的最后被关闭。但我们要求,每一个资源对象必须实现java.lang.AutoCloseable
包括实现了java.io.Closeable
的对象都可以被作为资源对象。
如果在Java SE 7 之前,我们关闭一个流对象,需要如下的写法:
static String readFirstLineFromFileWithFinallyBlock(String path)
throws IOException {
BufferedReader br = new BufferedReader(new FileReader(path));
try {
return br.readLine();
}catch(//...){
//...
}finally {
if (br != null) br.close();
}
}
将close()方法置于finally语句块中是一个常见的做法。
使用Java SE 7 之后,使用TryWithResources,我们就可以更优雅地关闭流对象了:
static String readFirstLineFromFile(String path) throws IOException {
try (BufferedReader br =
new BufferedReader(new FileReader(path))) {
return br.readLine();