我们在使用资源的时候,必须关闭资源,比如使用jdbc连接或者inputStream的时候,必须在finally中将资源关闭。然而有的时候我们会忘记关闭资源。那么有没有更好的方法呢?
SqlSession sqlSession = sqlSessionFactory.openSession() try{ //...... } finally { sqlSession.close(); }
从jdk1.7开始, Java 7增强了try语句的功能——它允许在try关键字后跟一对圆括号,圆括号可以声明,初始化一个或多个资源,此处的资源指得是那些必须在程序结束时必须关闭的资源(比如数据库连接,网络连接等),try语句在该语句结束时自动关闭这些资源。这种称为try-with-resources语句。
try (SqlSession sqlSession = sqlSessionFactory.openSession()) { //...... }
像这样的话,执行完sqlsession会自动关闭,不用我们在finally中关闭,也再也不用担心忘记关闭了。
那么为什么这样可以自动关闭资源呢?是不是所有的资源都可以这样关闭呢?
实际上只要这些资源实现类实现了Closeable或AutoCloseable接口,就可以自动关闭。比如Sqlsession它就是extends Closeable, Closeable extends AutoCloseable。
几乎所有的资源都可以用这种方式实现自动关闭资源,比如OutputStream,BufferedReader,PrintStream,InputStream等,都可以。据说到目前为止,只有JavaMail Transport对象不能利用这种方式实现自动关闭。
注意:如果try()里面有两个资源,用分号分开,资源的close方法的调用顺序与它们的创建顺序相反。
带有资源的try语句可以像一般的try语句一样具有catch和finally块。在try-with-resources语句中,任何catch或finally块都是在声明的资源被关闭后才会执行的。
举例说明:
/** * 关闭流测试 * 通过读写文件进行测试 */ public class ExceptionCloseTest { public static void main(String[] args) { copy(); } /** * 使用缓冲流完成文件的复制 */ private static void copy() { //1.创建缓冲流 BufferedInputStream bis = null; BufferedOutputStream bos = null; try{ //2.缓冲流的初始化 bis = new BufferedInputStream(new FileInputStream("D:\\a\\七月上.mp3")); bos = new BufferedOutputStream(new FileOutputStream("D:\\a\\3.mp3")); byte bytes[] = new byte[2048]; int len = 0; //3.读写操作 while((len=bis.read(bytes))!=-1){ bos.write(bytes,0,len); } bos.flush(); }catch(Exception e){ e.getStackTrace(); }finally{ /** * 关闭流的操作 最麻烦写法 对流逐个判断 如果流很多 要写很多个判断的方法 */ if(bis!=null){ try { bis.close(); } catch (IOException e) { e.printStackTrace(); } } if(bos!=null){ try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
上面关流的方式不是很友好 我们可以根据流的特性写一个方法去关闭(改变在finally部分)
package com.fpy.exception; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; /** * 关闭流测试 通过读写文件进行测试 */ public class ExceptionCloseTest { public static void main(String[] args) { copy(); } /** * 使用缓冲流完成文件的复制 */ private static void copy() { // 1.创建缓冲流 BufferedInputStream bis = null; BufferedOutputStream bos = null; try { // 2.缓冲流的初始化 bis = new BufferedInputStream(new FileInputStream("D:\\a\\七月上.mp3")); bos = new BufferedOutputStream(new FileOutputStream("D:\\a\\3.mp3")); byte bytes[] = new byte[2048]; int len = 0; // 3.读写操作 while ((len = bis.read(bytes)) != -1) { bos.write(bytes, 0, len); } bos.flush(); } catch (Exception e) { e.getStackTrace(); } finally { //作为实参传入close()自定义方法 close(bis); close(bos); } } /** * 基本上所学的流都实现了Closeable 接口 * 所以可以使用多态的知识进行简化操作 * @param clo 表面是Closeable类型 实际上传入的流是谁那么关闭的流就是谁 */ private static void close(Closeable clo) {//多态 if (clo != null) { try { clo.close(); } catch (IOException e) { e.printStackTrace(); } } } }
看到这里会发现 我们只需要一个方法即可完成关流的操作,那么还有没有更简单的方法呢?我自己不想手动去关流,能不能自动关流呢?
答案是可以的(改变在去掉finally部分)
package com.fpy.exception; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.Closeable; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /** * 关闭流测试 通过读写文件进行测试 * * @author Mr.Gao */ public class ExceptionCloseTest { public static void main(String[] args) { copy(); } /** * 使用缓冲流完成文件的复制 */ private static void copy() { // 1.创建缓冲流 /** * 使用java7的新特性 try(流的声明){ * 业务操作 * }catch(){}; * 不用再写关流的操作,内部自动完成资源的释放 * * 注意:没有 七月上1.mp3 资源 */ try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\a\\七月上1.mp3")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\a\\3.mp3"));) { byte bytes[] = new byte[2048]; int len = 0; // 3.读写操作 while ((len = bis.read(bytes)) != -1) { bos.write(bytes, 0, len); } bos.flush(); System.out.println("Suucess"); } catch (FileNotFoundException e) { //e.printStackTrace(); System.out.println(e.getMessage()); } catch (IOException e) { System.out.println(e.getMessage()); e.printStackTrace(); } } }
运行效果:
参考: