深入学习Java IO关闭

写这篇文章主要是本周排查一个问题的时候,看到一段没有正确关闭文件的代码,起初怀疑是这块导致的,最后虽然不是,但是还是有必要学习一下资源关闭的知识。
一.正确关闭资源的方式
在实际开发中,经常需要在程序中打开一些物理资源,如数据库连接,网络连接,磁盘文件等,打开这些资源之后必须显示关闭,否则将会引起资源泄露。
JVM不是提供了垃圾回收机制吗?JVM的垃圾回收机制不会回收这些资源吗?答案是不会,垃圾回收机制属于Java内存管理的一部分,它只是负责回收堆内存中分配出来的内存,至于程序中打开的物理资源,垃圾回收机制是无能为力的。那么既然需要关闭这些资源,就来看一下如何正确关闭资源吧。下面是一段Java关闭IO的代码:
public static void testCloseFileStream() {
          Objectobj = new Object();
          Objectobj2 = null;
          ObjectOutputStreamoos = null;
          ObjectInputStreamois = null;
          try {
              oos = new ObjectOutputStream(new FileOutputStream("a.bin"));
              ois = new ObjectInputStream(new FileInputStream("a.bin"));
              oos.writeObject(obj);
              oos.flush();
              obj2 = ois.readObject();
          }catch (Exception e ) {
              e.printStackTrace();
          }finally{
               //关闭资源
              if(oos!= null){//检查资源是否为null
                   try {
                        oos.close();
                   }catch (Exception e2 ) {
                        e2.printStackTrace();
                   }
              }
              if(ois!= null){
                   try {
                        ois.close();
                   }catch (Exception e2 ) {
                        e2.printStackTrace();
                   }
              }
          }
     }


上面代码主要功能是序列化,反序列化一个对象,这里为了方便就只是序列化一个Object对象了。代码中的finally块中是关闭资源的部分,首先为了保证文件能正常关闭,我们一定要在finally中关闭资源,保证关闭操作总是会被执行,其次关闭每个资源之前首先保证引用改资源的引用变量不为null,因为资源可能由于前面的某个异常并没有初始化成功,此时引用还是null,最后可以看到,oos和ois是在两个单独的try...catch块中,这样是为了保证关闭资源时引发的异常不会影响其他资源的关闭。(之前我也习惯将两个close放到一个try catch块中)

从Java7开始,资源的关闭有了新的方式。上面看到正确的关闭资源导致finally中代码非常臃肿,为了解决这个问题,Java7新增了自动关闭资源的try语句,它允许try关键字后紧跟一对圆括号,圆括号可以声明,初始化一个或多个资源,try语句会在该语句结束时自动关闭这些资源。需要注意的是,为了保证try语句可以正常关闭资源,这些资源实现类必须实现AutoCloseable或Closeable接口。
关闭代码如下所示:
public static void testCloseStream()throws IOException,ClassNotFoundException{
          Objectobj = new Object();
          Objectobj2 = null;
          try(ObjectOutputStreamoos = new ObjectOutputStream(new FileOutputStream("a.bin"));
              ObjectInputStreamois = new ObjectInputStream(new FileInputStream("a.bin"));     
              ){
              oos.writeObject(obj);
              oos.flush();
              obj2 = ois.readObject();
          }
     }


可以看到这样的关闭方式确实简洁了很多,不需要我们手动进行关闭,可以将注意力放到具体业务上,代码也很易懂。
二.不关闭IO有什么影响
不关闭或不正确关闭资源,会导致程序还在占用着资源,浪费资源,随着运行时间的增加,一方面会内存泄露,另一方面会导致其他利用资源的代码获取不到资源,这样需要资源的线程就会在获取资源上卡住。本周排查的问题刚开始就怀疑是资源没有正确关闭导致的。
三.IO流关闭顺序
我们在使用IO的时候,经常会存在IO嵌套的操作(就是将一个Stream的引用放在了当前Stream对象的一个属性中)。当前Stream对象发起close()操作时,会间接调用内部的Stream.close()方法来完成实际的动作,他自身可能会保存一个状态或做一些Buffer处理。另外,流在关闭的时候会判断当前流是否已经关闭,所以一个流上的close方法可以多次调用。既然关闭外层流会调用内部流的close方法,那么理论上关闭外层和关闭内层是一样的,不过有些小细节需要注意,拿BufferedOutputStreama来说,它嵌套了另一个OutputStream,如果程序中也有这个被嵌套的OutputStream的引用,直接调用它的close方法,那么这个BufferedOutputStream里面就有可能会有部分数据未输出,从而导致部分数据丢失。
一篇IO关闭顺序的文章可以供大家参考
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值