日常编程中,难免需要和文件打交道(本文就以文件为例了,通常我们都知道,用了东西就不能撒手不管,当我们打开了一个流时,则必须在try...cache...finally的finaly中将流关闭,保证流关闭代码的执行。
为什么流一定要关闭?
举个例子,在电脑打开word软件后,编辑写入内容,当内容写好后,你将它保存到桌面,然后,你在桌面打开该文件(千万不要关闭),而这是,你想删除该文件将提示无法删除,因为文件已打开。
java程序中,流为什么需要关闭,和这个例子也有着一定的联系。 为什么文件不能删除,因为文件已打开,系统资源被占用着。
为什么流一定要关闭?因为也是占用着系统资源,虽然gc可以回收,但是系统资源无法释放还是会占用内存空间。
当我们使用new 关键字获取一个InputStream()的实例时,不仅仅会在java内存中创建一个对象实例,而且还需要占用系统资源,如获取文件句炳。InputStream在内存中没有引用的时候,gc即可回收(无论流是否关闭),而流若没有关闭,虽然gc回收了对象的内存,但是系统资源的内存并没有释放。 若一个流如此,可能还没什么,但是在一个频繁读取文件的系统中,可能会积少成多导致内存的溢出 。 甚至,若积累了过多的流没有关闭,当有新请求需要打开流时候,会报FileNotFindExcetion(Too many open files).
造成该文件无法被读取,因此,关闭流是必须的。
在jdk1.7版本之前,在finally中将流关闭几乎是唯一的手段,但finally中的代码往往向个孤儿一样,因为他不是与业务相关的代码,并且,如果有多个流需要关闭,每次都需要在finally中调用close()不仅重复造轮子,而且代码还非常不美观,尤其是close()方法本身也会抛出异常,所以有需要在finally中写try...cache语句。
而在jdk1.7版本中,引入了一个AutoCloseable的接口,并在try...cache中添加了带资源的try..cache的机制,在退出try时,自动调用close方法。
public interface AutoCloseable {
void close() throws Exception;
细心的朋友可能还会发现,AutoCloseable接口还有一个子类Closeable,其也有close方法,并且向InputStream、OutputStream等流类也实现了Closeable接口,其实,这也是为带资源的try...cache准备的,谁让这个资源自能是实现AutoCloseable接口的类呢?
如何使用?
以FileInputStream为例
try(FileInputStream inputStream = new FileInputStream("/Users/xuyunjin/aaaa")) {
//业务代码
}catch (IOException e){
//异常处理
这样子写有什么好处?
inputStream仅在try{ }中有效,离开类try后,其引用就消失了,代表内存空间可以被GC回收。
当离开了try后,会自动调用inputStream的close方法,即使出现异常,也是先调用close方法在进入异常处理代码块,避免因忘记调用导致的各类问题。
注意:第二点说的,离开了try后,会自动调用inputStream的close方法,指的是离开
带资源的try中只能写入实现了AutoClose接口及其子接口的类,否则编译不同通过(这里和java的多态机制有关,需要强类型转化成为AutoClose后才能调用close()方法)
class FileReader implements AutoCloseable {
@Override
public void close() {
System.out.println("关闭流");
main方法(不出现异常的情况)
try(FileReader reader = new FileReader()) {
System.out.println("业务处理代码块");
}catch (Exception e){
System.out.println("异常处理代码块");
}finally {
System.out.println("finally");
业务处理代码块
finally
main方法(出现异常的情况)
try(FileReader reader = new FileReader()) {
System.out.println("业务处理代码块");
if (true){
System.out.println("模拟出现异常");
throw new Exception();
}catch (Exception e){
System.out.println("异常处理代码块");
}finally {
System.out.println("finally");
业务处理代码块
模拟出现异常
异常处理代码块
finally
其实本文没有什么知识点,算不上干货,比较对于一个搬砖人来说,谁都直到不关闭流的代价是什么。因此,本文只是在介绍AutoCloseable和带资源的try...cache这种机制,不用这种机制,原有finally关闭流也能实现,同时效果一模一样。但是使用该机制后,代码逻辑则可以更加清晰,代码也更好看了。