在JDK 7中,引入了try-with-resource
用于替代在try-catch-finally
中手动的资源关闭
通常需要我们手动释放的资源包括:
- 文件/流资源
- socket资源
- 数据库连接资源
这些资源不能自动的被回收,长时间无效占用,当超过最大限制后,将会无资源可用,最终导致系统无法正常运行
以文件拷贝为例演示JDK 7之前和引入try-with-resource
后的差异
- 使用
try-catch-finally
实现文件拷贝的资源管理
输入输出流需要在try块外先定义,并在finally中按初始化顺序的倒序逐一进行释放
@Test
public void copyFile() {
//路径
String originalUrl = "lib/FileCopy.java";
String outUrl = "outTest/out.txt";
//资源对象
FileInputStream fileInputStream = null;
FileOutputStream fileOutputStream = null;
try {
//初始化资源对象
fileInputStream = new FileInputStream(originalUrl);
fileOutputStream = new FileOutputStream(outUrl);
int content;
//读取并写入
while ((content = fileInputStream.read()) != -1) {
fileOutputStream.write(content);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {//资源关闭
if (fileOutputStream != null) {
try {
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fileInputStream!= null) {
try {
fileInputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
使用try-with-resource
实现文件拷贝的资源管理
try-with-resource
的结构是:
try (
//资源定义
) {
//逻辑代码
} catch(Exception e) {
//异常处理
}
与try-catch-finally
相比,在try后多了一对小括号用于资源定义,且不需要再手动的关闭资源了
具体代码如下:
/**
* 基于JDK7及以后的
* try - with - resource
*/
@Test
public void newCopyFile() {
//路径
String originalUrl = "lib/FileCopy.java";
String outUrl = "outTest/out.txt";
/**
* 小括号内定义资源,不需要显示的关闭资源,会自动的关闭
* try - with - resource
*/
try (
//定义资源
FileInputStream fileInputStream = new FileInputStream(originalUrl);
FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
) {
int content;
while ((content = fileInputStream.read()) != -1) {
fileOutputStream.write(content);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
从上面两段代码可以看出,在try-with-resource
中的小括号内定义资源就不用再手动的进行释放了
为了更清楚的弄明白是怎样实现了,查看下反编译的代码
这里反编译的代码来自IDEA编译后的target文件下自动反编译的文件。
使用try-with-resource
的反编译代码如下
@Test
public void newCopyFile() {
String originalUrl = "lib/FileCopy.java";
String outUrl = "outTest/out.txt";
try {
FileInputStream fileInputStream = new FileInputStream(originalUrl);
Throwable var4 = null;
try {
FileOutputStream fileOutputStream = new FileOutputStream(outUrl);
Throwable var6 = null;
try {
int content;
try {
while((content = fileInputStream.read()) != -1) {
fileOutputStream.write(content);
}
} catch (Throwable var33) {
var6 = var33;
throw var33;
}
} finally {
if (fileOutputStream != null) {
if (var6 != null) {
try {
fileOutputStream.close();
} catch (Throwable var32) {
var6.addSuppressed(var32);
}
} else {
fileOutputStream.close();
}
}
}
} catch (Throwable var35) {
var4 = var35;
throw var35;
} finally {
if (fileInputStream != null) {
if (var4 != null) {
try {
fileInputStream.close();
} catch (Throwable var31) {
var4.addSuppressed(var31);
}
} else {
fileInputStream.close();
}
}
}
} catch (FileNotFoundException var37) {
var37.printStackTrace();
} catch (IOException var38) {
var38.printStackTrace();
}
}
可以很容易的发现,编译器将try-with-resource
格式的代码编译成了嵌套的try-catch-finally
的形式,所以可以证明try-with-resource
能实现自动添加资源释放
使用注意点:
- 资源需要实现AutoCloseable接口
- 资源对象被return的情况下,由调用方关闭
- ByteArrayInputStream等不需要检查关闭资源对象
- 使用socket获取的InputStream和OutputStream对象不需要关闭
(如果直接关闭会关闭socket整个连接,需要调用socket的方法进行关闭-shutdowInput 和 shutdownOutput)