我们在使用资源的时候,必须关闭资源,比如使用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();
}
}
}
运行效果:

参考: